AWS for SAP

Building SAP Business Applications using AWS Services

Introduction

To modernize their SAP landscape, many AWS customers are leveraging the breadth and depth of AWS services to develop new applications and functionalities in accordance with SAP’s “clean core” approach. This simplifies future upgrades and extensibility, thus allowing them to innovate at a rapid pace using AWS services. To meet business demands faster and to provide a seamless user experience, customers are looking to accelerate SAP mobile and web-based development using developer-friendly open-source libraries and UI components with continuous deployment and hosting capabilities. This gives customers an additional option on top of using SAP Business Technology Platform (SAP BTP) services in accordance with the AWS/SAP Joint Reference Architecture, which you can read about here.

The SAP User interface has evolved over time with SAP Graphical User Interface, Business Server Pages and Web Dynpro ABAP to develop web applications, and SAPUI5 embracing web standards. With OpenUI5, SAP provides the open-source variant of UI5. In addition to SAP UI5, developers outside of the SAP ecosystem can now leverage open-source technologies and frameworks of their choice to develop applications connecting to SAP. Open-source libraries such as React use virtual document object model which renders web pages faster, provides reusable components, lets you build web and native apps using the same skill and has a community of millions of developers. SAP customers in retail business might want to develop an in-store application showing inventory of displayed products to customers or develop a survey application about in-store experience to customers.

This blog shows how you can build innovative and feature-rich applications consuming data from SAP systems using AWS Amplify. With Amplify, frontend web and mobile developers can easily build, ship, and host full-stack applications on AWS. Amplify consists of a set of tools (open-source framework, visual development environment, console) and services (web app and static website hosting) to accelerate the development of mobile and web applications on AWS. Amplify leverages a core set of AWS Services to offer capabilities such as offline data, authentication, analytics, push notifications, and many more. Developers can easily create new backend for authentication, REST APIs, storage and add other supported functionalities by running Amplify Command Line Interface (CLI) commands to create the required AWS resources.

Overview

I’ll show how you can build, deploy, and host a React based web application using Amplify. React is a JavaScript library for building user interfaces. Amplify CLI does the heavy lifting by creating a REST API in Amazon API Gateway , Amazon Cognito resources, AWS Lambda function and storing passwords in AWS Secrets Manager. Users access React web application from the web browser and get authenticated via Cognito user pools. The REST API endpoint invokes the Lambda function which in turn calls the SAP OData endpoint present in the SAP system to retrieve the list of products which will be displayed in the React web application.

Architecture of React Web Application connecting to SAP system using AWS Amplify and other AWS services

Walkthrough

Below are the high-level steps performed as part of the Amplify deployment.

  1. Identify SAP OData Service
  2. Set up AWS Cloud9 Development Environment
  3. Create AWS Lambda layer
  4. Install and configure Amplify Command Line Interface
  5. Create an Amplify project and backend resources
  6. Modify Lambda function
  7. Create client-side user interface and host application
  8. Publish and test the application

Prerequisites

For this walkthrough, you should have the following prerequisites:

1. Identify SAP OData Service

I will use the Enterprise Procurement Model (EPM) OData service (EPM_REF_APPS_SHOP_SRV) in this demo. If you want to know more about what this OData service provides, refer to OData Exploration with EPM . This OData service has an entity set called “Products”, which gives the list of products and will be used in this application.

For instructions on how to activate the OData service, refer to Activate Available OData in SAP Gateway. To test OData service, you can use the SAP Gateway Client (Transaction Code /IWFND/GW_CLIENT), with the following Request URI.

/sap/opu/odata/sap/EPM_REF_APPS_SHOP_SRV/Products?$format=json

The following screenshot shows JSON output of “EPM_REF_APPS_SHOP_SRV” OData service from SAP Gateway Client. SAP Gateway Client showing output of OData Service

2. Set up AWS Cloud9 Development Environment

AWS Cloud9 is a cloud-based integrated development environment (IDE) that lets you write, run, and debug your code with just a browser.

2.1. Sign in to the AWS Management Console and open the AWS Cloud9 console at https://console.aws.amazon.com/cloud9. Choose Create environment and provide name with description (optional). Select “t3.small” for the Instance type and verify that the Platform is set to “Amazon Linux 2”. Leave all other fields as default. Choose Create to create your environment.

Create AWS Cloud9 Development Environment

2.2. In the AWS Cloud9 console, choose Open link next to the environment name you created to launch the IDE.

Open AWS Cloud9 IDE

2.3. In the terminal window at the bottom portion of the IDE, use the following command to install Python 3.8 from the amazon-linux-extras repository.

sudo amazon-linux-extras install -y python3.8

2.4. Use the following command to create a Python virtual environment and to activate it.

python3.8 -m venv .venv
source .venv/bin/activate

2.5. Install pipenv, urllib3 and xdg-utils package by using the following command.

pip3.8 install pipenv
pip3.8 install urllib3==1.26.15
sudo yum -y install xdg-utils

3. Create AWS Lambda layer

In this step you’ll create a Lambda layer which will package the python requests library. This Lambda layer can be reused across multiple Lambda functions.

3.1. Create a python folder by running the following command in AWS Cloud9.

mkdir python

3.2. Install the Requests library files into the python folder by running the following command.

python3.8 -m pip install requests -t python/

3.3. Zip the contents of the python folder into a layer.zip file by running the following command.

zip -r layer.zip python

3.4. Use the following command to publish the Lambda layer. Replace us-east-1 with your AWS Region. Make a note of LayerVersionArn from the output of the command. You will need this in step 5.

aws lambda publish-layer-version --layer-name py-layer --zip-file fileb://layer.zip --compatible-runtimes python3.8 --region us-east-1

Publish AWS Lambda Layer and retrieve ARN

4. Install and configure Amplify Command Line Interface

The Amplify CLI is a unified toolchain to create AWS cloud services for your app.

4.1. To install the Amplify CLI, use the following command in AWS Cloud9 IDE.

npm install -g @aws-amplify/cli

4.2. Configure Amplify by running the following command.

amplify configure

The command will prompt you to select AWS region and to provide a user name. Amplify CLI will prompt to complete the IAM user creation using AWS console. Select the URL to navigate to AWS console as shown in the following screenshot.

Configuring AWS Amplify

Create a user with AdministratorAccess-Amplify permission.

Create an IAM User

Once the IAM user is created, Amplify CLI will ask you to provide the accessKeyId and the secretAccessKey which you can enter from the IAM AWS console. Leave the profile name as default.

Configure AWS Amplify with IAM user

5. Create an Amplify project and backend resources

5.1. Create a new React app named productlistapp with the following command in AWS Cloud9 IDE and then move inside the project folder.

npx -y create-react-app productlistapp
cd productlistapp

5.2. The next step is to set up Amplify and create the backend services to support the app. Initialize amplify with the following command.

amplify init -y

5.3. Use the following command to add an API resource.

amplify add api

 You’ll see an interactive workflow. Select and provide the values as shown below.

Select from one of the below mentioned services: REST
Provide a friendly name for your resource to be used as a label for this category in the project: · productlistapi
Provide a path (e.g., /book/{isbn}): /items
Only one option for [Choose a Lambda source]. Selecting [Create a new Lambda function].
Provide an AWS Lambda function name: productlistfunction
Choose the runtime that you want to use: Python
Do you want to configure advanced settings? Yes
Do you want to access other resources in this project from your Lambda function? No
Do you want to invoke this function on a recurring schedule? No
Do you want to enable Lambda layers for this function? Yes
Enter up to 5 existing Lambda layer ARNs (comma-separated): Enter Lambda Layer ARN from step 3
Do you want to configure environment variables for this function? Yes
Enter the environment variable name: sapProtocol
Enter the environment variable value: Enter SAP URL protocol here
Select what you want to do with environment variables: Add new environment variable
Enter the environment variable name: sapHostName
Enter the environment variable value: Enter SAP hostname here
Select what you want to do with environment variables: Add new environment variable
Enter the environment variable name: sapPort
Enter the environment variable value: Enter SAP HTTP(S) port number here
Select what you want to do with environment variables: Add new environment variable
Enter the environment variable name: odpEntitySetName
Enter the environment variable value: Products
Select what you want to do with environment variables: Add new environment variable
Enter the environment variable name: odpServiceName
Enter the environment variable value: EPM_REF_APPS_SHOP_SRV
Select what you want to do with environment variables: I'm done
Do you want to configure secret values this function can access? Yes
Enter a secret name (this is the key used to look up the secret value): sapUser
Enter the value for sapUser: Enter SAP user ID here
What do you want to do? Add a secret
Enter a secret name (this is the key used to look up the secret value): sapPassword
Enter the value for sapPassword: Enter SAP password here
What do you want to do? I'm done
Do you want to edit the local lambda function now? No
Restrict API access? (Y/n) No
Do you want to add another path? (y/N) No

The following screenshot shows the amplify add api workflow.

Workflow of amplify add api command

5.4. Use the following command to add authentication.

amplify add auth

You’ll see an interactive workflow. Select options as shown in the following screenshot.

Workflow of amplify add auth command

I’ve selected Amazon Cognito as the main authentication provider. Cognito is a robust user directory service that handles user registration, authentication, account recovery and other operations.

5.5. Use the following command to push the api resources to amplify project.

amplify push -y

6. Modify Lambda function

In AWS Cloud9 IDE, click on the AWS Explorer icon in the left navigation pane. Choose your AWS region and expand Lambda.

Download AWS Lambda function to AWS Cloud9

If you have followed the naming convention from previous step, choose the Lambda function productlistfunction-dev. Right click on the function and choose “Download…”. Select the highlighted workspace folder. The Lambda function created by Amplify CLI will be downloaded to your AWS Cloud9 workspace.

Expand the folder productlistfunction-dev and open index.py and replace the contents of the file with the following python code. Choose File, Save

import boto3
import json
import os
import requests
from requests.auth import HTTPBasicAuth

client = boto3.client('ssm')

def handler(event,context):
    sapUser = _get_ssm_secure_parameter(os.environ['sapUser'])
    sapPassword = _get_ssm_secure_parameter(os.environ['sapPassword'])
    url = _get_base_url(os.environ['sapProtocol'], os.environ['sapHostName'], os.environ['sapPort'], os.environ['odpServiceName']) + "/" + os.environ['odpEntitySetName'] + "?$format=json"
    sapresponse =  requests.get(url,auth=HTTPBasicAuth(sapUser,sapPassword),verify=False)
    sapresponsebody = json.loads(sapresponse.text)
    result = sapresponsebody.pop('d',None).pop('results',None)
    return {
        'statusCode': 200,
        'headers': {
          'Access-Control-Allow-Headers': '*',
          'Access-Control-Allow-Origin': '*',
          'Access-Control-Allow-Methods': 'OPTIONS,POST,GET'
        },
        'body': json.dumps(result)
  }

# -------------------------------------------------------
# Get parameter from Systems Manager Paramter Store
# -------------------------------------------------------
def _get_ssm_secure_parameter(parameterName):
  resp = client.get_parameter(
    Name=parameterName,
    WithDecryption=True
  )
  return resp['Parameter']['Value']
    
# ------------------------------------
# Get base url for HTTP calls to SAP
# ------------------------------------
def _get_base_url(sapProtocol,sapHostName,sapPort,odpServiceName):
    return sapProtocol + "://" + sapHostName + ":" + sapPort + "/sap/opu/odata/SAP/" + odpServiceName

Right click on the Lambda function from the left navigation pane of AWS Cloud9 and choose “Upload Lambda…”. Select the AWS region and then select productlistfunction-dev . This will deploy the changes. A message “Uploaded Lambda function: productlistfunction-dev” is shown at the top on successful upload.

Upload AWS Lambda function from AWS Cloud9

7. Create client-side user interface and host application

7.1. Use the following command in AWS Cloud9 to install Amplify JavaScript libraries and Amplify UI

npm install aws-amplify @aws-amplify/ui-react

7.2. Expand productlistapp folder and open src/index.js

Add the following code below the last import. Choose File, Save

import { Amplify } from 'aws-amplify';
import awsExports from './aws-exports';
Amplify.configure(awsExports);

Contents of index.js file

7.3. In productlistapp folder, open src/App.js

App.js file in the project structure

Replace the contents of App.js file with the following code. Choose File, Save

import React, { useState, useEffect } from 'react'
import { API } from 'aws-amplify'
import { Table, TableCell, TableBody, TableHead, TableRow, Rating, Loader, withAuthenticator, Button, Flex, Heading } from '@aws-amplify/ui-react';
import '@aws-amplify/ui-react/styles.css';

const apiName = 'productlistapi';
const path = '/items';
const myInit = {
  headers: {}, 
  response: true,
  queryStringParameters: {}
};

function App({ signOut, user }) {
  const [result, setResult] = useState([])
  const [loading, setLoading] = useState(true);

  async function getResults() {
    API.get(apiName, path, myInit)
      .then((response) => {
           setLoading(false);
        setResult(response.data)
      })
      .catch((error) => {
           setLoading(false);
      });
  }

  useEffect(() => {
    getResults()
  }, [])

 if(loading) return  <div style={{ textAlign: "center" }}> <Loader width="5rem" height="5rem" /> </div>

 return (
    <div className="App">
    <Flex padding="0.25rem">
      <Heading level={4}>Welcome, {user.username}</Heading>
      <Button style={{ marginLeft: "auto" }} onClick={signOut}>Sign out</Button>
    </Flex>
    <Table variation="bordered">
    <TableHead style={{ backgroundColor: '#E2E2E2' }}>
      <TableRow style={{ textAlign: "left" }}>
        <TableCell as="th">Product ID</TableCell>
        <TableCell as="th">Product Name</TableCell>
        <TableCell as="th">Product Category</TableCell>
        <TableCell as="th">Product Rating</TableCell>
        <TableCell as="th">Price</TableCell>
        <TableCell as="th">Dimension</TableCell>
        <TableCell as="th">Weight</TableCell>
        <TableCell as="th">Supplier ID</TableCell>
        <TableCell as="th">Supplier Name</TableCell>
      </TableRow>
    </TableHead>
    <TableBody>
     {
        result.map((data, index) => (
             <TableRow  style={{ textAlign: "left" }}>
                <TableCell>{data.Id}</TableCell>
                <TableCell>{data.Name}</TableCell>
                <TableCell>{data.MainCategoryName}</TableCell>
                <TableCell><Rating value={data.AverageRating} maxValue={5}/></TableCell>
                <TableCell>{data.Price} {data.CurrencyCode}</TableCell>
                <TableCell>{data.DimensionWidth}x{data.DimensionHeight}x{data.DimensionDepth} {data.DimensionUnit} </TableCell>
                <TableCell>{data.WeightMeasure} {data.WeightUnit}</TableCell>
                <TableCell>{data.SupplierId}</TableCell>
                <TableCell>{data.SupplierName}</TableCell>
              </TableRow>
        ))
      }
    </TableBody>
  </Table>
    </div>
  );
}

export default withAuthenticator(App);

7.4. Use the following command to add hosting configuration. Select options as per the following screenshot.

amplify add hosting

AWS Amplify Hosting Configuration

8. Publish and test the application

Build and publish the application with the following command.

amplify publish -y

On successful execution of the command, the hosting URL will be displayed as shown below.

Output of amplify publish command

Open the URL in the browser . You’ll see a Sign In / Sign up page. Choose Create Account and provide details.

React Application with Sign In and Sign Up functionality

Enter the confirmation code sent your email address and choose Confirm.

React application showing Account verification functionality

You will see the web application that displays the product data fetched from SAP that resembles the example in the following image.

React Application displaying products from SAP

Conclusion

In this blog, I’ve shown how you can build a React web application using Amplify consuming data from SAP. You can use Amplify to add additional features such as data store for offline scenarios, analytics to track web page metrics and others to your application with a few lines of code. In addition to React, you can use other popular frameworks such as Angular, Vue, Flutter and others. Developers can develop and deploy cloud-powered scalable mobile and web SAP applications using Amplify to meet business demands faster.

Visit the AWS for SAP page to learn why thousands of customers choose AWS to migrate, modernize, and innovate with their SAP workloads.