This public repository is read-only and no longer maintained. For the latest sample code repositories, visit the SAP Samples organization.
This sample illustrates the essentials for calling a SAP Business Technology Platform (BTP) service API from a Java Spring Boot application running outside of SAP BTP. This code targets the SAP Workflow service, but the same essentials would apply to most SAP BTP service APIs.
An Important Message Regarding Indirect Use of SAP APIs |
---|
There may be a licensing impact in using SAP APIs from an external application such as what's described in this code sample. This is especially true if API requests are being made on behalf of users who are not already covered by your SAP Licensing or Subscription agreements. You should consult this document and your local SAP representative to understand the business and licensing impact for production use of SAP APIs such as the SAP Workflow service described in this sample. |
- Invoking the SAP Workflow service APIs from outside of SAP BTP
- Overview
- Description
- Prerequisites
- Quickstarts
- Resources
This is a simple Spring Boot application capable of running in a range of environments. It has been tested running locally on the developer's computer, in a local Kubernetes cluster, and in cloud-based Kubernetes clusters.
The application exposes two API endpoints on port 8080
- GET
/workflow/definition/list
- returns list of workflow definitions
- POST
/workflow/instance/new
- triggers the creation of a new workflow instance
Both endpoints connect to the SAP Workflow service.
To successfully make connection to the Workflow service, application first
makes a call to XSUAA, the XSA OAuth 2.0 authorization server, running on SAP
BTP to request a JWT access token. Then, using the JWT token as an
Authorization
header, Workflow APIs are invoked.
To make a successful call to both authorization server and Workflow service,
application requires four environment variables to be set: UAA_URL
,
UAA_CLIENTID
, UAA_CLIENTSECRET
, and ENDPOINTS_WORKFLOW_REST_URL
.
The exact values for these environment variables are instance-specific to the
XSUAA service running in your SAP BTP, Cloud Foundry environment space. Values
were issued by the Cloud Foundry Service Broker when the XSUAA instance was created.
Two Workflow API endpoints utilized in the application are
/v1/workflow-definitions
and /v1/workflow-instances
and already
have been defined in the application.yml.
Note: This is a sample application that is being intentionally kept simple. A production-ready version would require (at minimum) appropriate authorization security for the application's REST API endpoints along with occasional refresh of an expired JWT token
Reasonably current versions of a Java JDK and Gradle are required to compile and run this sample.
Calling any SAP BTP service typically requires that you create an instance of that service first. If you don't have an instance of the Workflow service, you can use the exercises described in the SAP Workflow CodeJam to create the Workflow and XSUAA services required in this sample.
Successful completion of SAP Workflow CodeJam should give you the following:
- Workflow Service running in SAP BTP
- An instance of the XSUAA authorization service
- User assigned with correct roles
- One Workflow Definition defined
- Values for the environment variables (the exact procedure for extracting these
variables are described in Step 06
of the CodeJam exercises)
endpoints.workflow_rest_url
uaa.clientid
uaa.clientsecret
uaa.url
If you already have an existing Workflow Service, you can probably still apply the instructions from Step 06 of the CodeJam exercises to extract the variable values you'll need.
- Quickstart for Running the Application Locally
- Quickstart for Creating Docker Image
- Quickstart for Deploying Containerized Application to Local Kubernetes Cluster
- Quickstart for Deploying Containerized Application to EKS
Please make sure you have completed the required prerequisites before continuing.
- Open up a command line tool of your choice
- Clone the repo
git clone https://github.com/SAP-samples/cloud-workflow-spring-sample.git
- Change your current working directory to root of cloned repo
cd cloud-workflow-spring-sample
- Set four environment variables to appropriate values
export UAA_URL='https://xxxxxxxxxxxxxxxxxx.authentication.eu10.hana.ondemand.com' export UAA_CLIENTID='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' export UAA_CLIENTSECRET='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' export ENDPOINTS_WORKFLOW_REST_URL='https://xxxxxxxxxxxxxx/workflow-service/rest'
UAA_URL
should be set to the value ofuaa.url
UAA_CLIENTID
should be set to the value ofuaa.clientid
UAA_CLIENTSECRET
should be set to the value ofuaa.clientsecret
ENDPOINTS_WORKFLOW_REST_URL
should be set to the value ofendpoints.workflow_rest_url
- Run application using gradlew
./gradlew clean build bootRun
- Once application is up, you can validate that application is running by
navigating to
localhost:8080
. Swagger UI have been added to this application to help visualize and interact with the two endpoints. - (Optional) Try out
/workflow/instance/new
endpoint with value from the CodeJam and see if you get the same response.{ "definitionId" : "orderprocess", "context": { "request": { "Id": "HT-1003", "Quantity": 25 } } }
- After exploring, please don't forget to stop the running application.
There are two ways to create a docker image for spring boot project. Both requires
docker to either create and/or validate the image.
Please choose one of the following options to create an image, both options will
create an image sap-cloud-workflow-spring-sample:0.0.1-SNAPSHOT
.
-
Use the
Dockerfile
that's available in the project root directory to create an image using ajar
file located in/builds/libs
directory.docker build --build-arg JAR_FILE=/build/libs/*.jar -t sap-cloud-workflow-spring-sample:0.0.1-SNAPSHOT .
Note: Running
./gradlew clean build
builds ajar
in./builds/libs
folder. -
Run the following command to validate that image has been created successfully.
docker images
Output should look similar to below
REPOSITORY TAG IMAGE ID CREATED SIZE sap-cloud-workflow-spring-sample 0.0.1-SNAPSHOT xxxxxxxxxxxx 49 seconds ago 317MB
-
Run the following command to validate the image. Running the image will produce same result as running the app locally. Once the app is running, you should be able to navigate to
localhost:8080
and see the same Swagger UI page as before.docker run \ -e UAA_URL='https://xxxxxxxxxxxxxxxxxx.authentication.eu10.hana.ondemand.com' \ -e UAA_CLIENTID='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \ -e UAA_CLIENTSECRET='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \ -e ENDPOINTS_WORKFLOW_REST_URL='https://xxxxxxxxxxxxxx/workflow-service/rest' \ -p 8080:8080 sap-cloud-workflow-spring-sample:0.0.1-SNAPSHOT
-
After exploring, please don't forget to stop the running image.
Spring Boot 2.3.0.RELEASE includes buildpack support for both
Maven and Gradle which allows you to use gradle
/mvn
command to create an image
without a Dockerfile
.
-
Run the following to create an image using
gradlew
./gradlew bootBuildImage
-
Run the following command to validate that image has been created successfully.
docker images
Output should look similar to below
REPOSITORY TAG IMAGE ID CREATED SIZE sap-cloud-workflow-spring-sample 0.0.1-SNAPSHOT xxxxxxxxxxxx 49 seconds ago 317MB
-
Run the following command to validate the image. Running the image will produce same result as running the app locally. Once the app is running, you should be able to navigate to
localhost:8080
and see the same Swagger UI page as before.docker run \ -e UAA_URL='https://xxxxxxxxxxxxxxxxxx.authentication.eu10.hana.ondemand.com' \ -e UAA_CLIENTID='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \ -e UAA_CLIENTSECRET='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \ -e ENDPOINTS_WORKFLOW_REST_URL='https://xxxxxxxxxxxxxx/workflow-service/rest' \ -p 8080:8080 sap-cloud-workflow-spring-sample:0.0.1-SNAPSHOT
-
After exploring, please don't forget to stop the running image.
This quickstart requires a Kubernetes Cluster running locally and kubectl
CLI
- Set kubectl config with correct Kubernetes cluster.
- Run the following command to create a secret
sap-cloud-workflow-spring-sample-secret
for environment variables to be used in the cluster.kubectl create secret generic sap-cloud-workflow-spring-sample-secret \ --from-literal=UAA_URL='https://xxxxxxxxxxxxxxxxxx.authentication.eu10.hana.ondemand.com' \ --from-literal=UAA_CLIENTID='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \ --from-literal=UAA_CLIENTSECRET='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \ --from-literal=ENDPOINTS_WORKFLOW_REST_URL='https://xxxxxxxxxxxxxx/workflow-service/rest'
- Run the following command to create a deployment using the image and secret
created in the previous step. Deployment yaml file
is provided for you to use.
kubectl create -f kubernetes/local/deployment.yaml
- Create a service to expose the deployment on port
8080
.kubectl expose deployment/sap-cloud-workflow-spring-sample --type=LoadBalancer --port=8080
- Validate application is running and exposed by navigating to
localhost:8080
. - After exploring, clean up resources by deleting deployment, service and secret created.
kubectl delete svc sap-cloud-workflow-spring-sample \ && kubectl delete deployment sap-cloud-workflow-spring-sample \ && kubectl delete secret sap-cloud-workflow-spring-sample-secret
You were able to use a local image for your local Kubernetes cluster, but once you start using Kubernetes service from different hyperscalers, you will need to start thinking about where to pull your images from.
There are two types of registries you can choose from
- A public registry like Docker Hub
- A private registry like AWS Elastic Container Registry, Azure Container Registry, Google Container Registry, and more
Below is an example of how to upload image created in a previous step into ECR. Please upload an image to either a public or private registry before continuing. If an image is uploaded to a public registry, please skip creating docker-registry secret from the steps below.
AWS_ACCOUNT_ID=<aws account id>
REGION=<region>
aws ecr get-login-password --region $REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com
aws ecr create-repository --repository-name sap-cloud-workflow-spring-sample-aws-ecr --image-scanning-configuration scanOnPush=true --region $REGION
docker tag sap-cloud-workflow-spring-sample-aws-ecr:0.0.1-SNAPSHOT $AWS_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/sap-cloud-workflow-spring-sample-aws-ecr:0.0.1-SNAPSHOT
docker push $AWS_ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/sap-cloud-workflow-spring-sample-aws-ecr:0.0.1-SNAPSHOT
Once uploaded to a container registry, follow the same steps as local Kubernetes cluster to
deploy the sample application. Differences between deploying to local and cloud cluster are
creating additional secret to pull an image from a private registry and a change to
deployment.yaml
to use the new secret.
-
Create a secret
sap-cloud-workflow-spring-sample-aws-ecr
to pull images from a private container registry.AWS_ACCOUNT_ID=<aws account id> REGION=<region> EMAIL=<email> kubectl create secret docker-registry sap-cloud-workflow-spring-sample-aws-ecr \ --docker-server=https://$AWS_ACCOUNT_ID.dkr.ecr.$REGION.amazonaws.com \ --docker-username=AWS \ --docker-password=$(aws ecr get-login-password --region $REGION) \ --docker-email=$EMAIL
-
Create a secret
sap-cloud-workflow-spring-sample-secret
for environment variables to be used in the cluster.kubectl create secret generic sap-cloud-workflow-spring-sample-secret \ --from-literal=UAA_URL='https://xxxxxxxxxxxxxxxxxx.authentication.eu10.hana.ondemand.com' \ --from-literal=UAA_CLIENTID='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \ --from-literal=UAA_CLIENTSECRET='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \ --from-literal=ENDPOINTS_WORKFLOW_REST_URL='https://xxxxxxxxxxxxxx/workflow-service/rest'
-
Open up
deployment.yaml
file under/kubernetes/aws/
directory and replace<aws account id>
with your own. Then, run the following to create a deployment.kubectl create -f kubernetes/aws/deployment.yaml
Note: directory of deployment.yaml have changed from /local to /aws
-
Create a service to expose the deployment.
kubectl expose deployment/sap-cloud-workflow-spring-sample --type=LoadBalancer --port=8080
-
Validate application is running and exposed by navigating to external-ip allocated by the cloud provider. Run the following to grab the external ip/address and navigate to it on port 8080 to see same swagger page as before.
kubectl get svc sap-cloud-workflow-spring-sample -o jsonpath={.status.loadBalancer.ingress[].hostname}
Note: Assigning an external IP can take more than a minute
-
After exploring, clean up resources by deleting deployment, service and secret created.
kubectl delete svc sap-cloud-workflow-spring-sample \ && kubectl delete deployment sap-cloud-workflow-spring-sample \ && kubectl delete secret sap-cloud-workflow-spring-sample-secret \ && kubectl delete secret sap-cloud-workflow-spring-sample-aws-ecr
Copyright (c) 2020 SAP SE or an SAP affiliate company. All rights reserved. This project is licensed under the Apache Software License, version 2.0 except as noted otherwise in the LICENSE file.