Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
CarlosRoggan
Product and Topic Expert
Product and Topic Expert
2,274
This blog is part of a series of tutorials explaining the usage of SAP Cloud Platform Backend service in detail.

This blog is like an appendix:
We learned how to call API from REST client tool (e.g. Postman)
It is complicated, due to OAuth flow
So we learned a lot if interesting things around OAuth:
What is OAuth? And "Authorization Code" ?
How to call my API from node.js application?
And more...

In all those great blogs we learned how to do the manual steps to overcome the OAuth protection
That was good learning – and we got used to it and it is OK

Now I’d like to propose an alternative: use App Router
Deploy Application Router which routes to Backend service API
It is easy, just requires 3 little files

Advantage: App Router handles the OAuth flow for us (we need only Basic Authentication)
Disadvantage: Some effort to configure and deploy App Router (it is easy)

To learn about App Router you can follow my little series: part 1 and part 2 and part 3
In this blog we're just doing the required steps:

Create App Router, redirecting to Backend service, facilitating calls from REST client

Prerequisites


Some APIs created in SAP Cloud Platform Backend service and you user has role to access them
You might need node.js installed on your machine, including configured SAP registry (see here)

Preparation


We’re going to create an application and deploy it to Cloud Foundry
This application wraps the App Router
It needs to be bound to an instance of XSUAA
That instance needs to contain the scope required by Backend service

To create such instance, see here
Note:
For the present tutorial, we don’t need to create Service Key

In our example, we use the following name for the XSUAA service instance:
"XsuaaForAppRouterWithBs"

Create App Router Configuration App


Create application structure


On your local file system, create files and folders like shown below

- C:\dev\app
- manifest.yml
- C:\dev\app\approuter
- package.json
- xs-app.json


Configuration


manifest.yml
---
applications:
- name: ApprouterToBackendservice
host: tobs
path: approuter
memory: 128M
services:
- XsuaaForAppRouterWithBs
env:
destinations: >
[
{
"name": "backendservice_v2",
"url": "https://backend-service-api.cfapps.eu10.hana.ondemand.com/odatav2/DEFAULT/",
"forwardAuthToken": true
},
{
"name": "backendservice_v4",
"url": "https://backend-service-api.cfapps.eu10.hana.ondemand.com/odatav4/DEFAULT/",
"forwardAuthToken": true
}
]

Explanation:
We create a destination pointing to the root URL of an OData v2 service in Backend service
A second destination is meant for v4 services
In both cases, App Router does the OAuth flow and forward the access token to Backend service
Furthermore, we define a binding to an existing XSUAA instance called "XsuaaForAppRouterWithBs"
If you’re using an XSUAA instance with different name, you need to adapt the name
We define a short host: tobs, because our app is only used to redirect to Backend service
If you get an error during deployment, make sure to change the host to some unique name

xs-app.json
{
"authenticationMethod": "route",
"routes": [
{
"authenticationType": "basic",
"csrfProtection": false,
"source": "^/bsv2/(.*)$",
"target": "$1",
"destination": "backendservice_v2"
},
{
"authenticationType": "basic",
"csrfProtection": false,
"source": "^/bsv4/(.*)$",
"target": "$1",
"destination": "backendservice_v4"
}
]
}

 

Explanation:
We define a route which points to the v2 root URL. To access this, route, we define a short URI-segment bsv2 (points to Backend service, OData V2 services)
That entry point requires "only" "Basic Authentication"
Furthermore, the x-csrf-token is not required (usually it is)
Similar configuration for OData V4 services

package.json
{
"name": "myapprouter",
"scripts": {
"start": "node node_modules/@sap/approuter/approuter.js"
},
"dependencies": {
"@sap/approuter": "^6.0.1"
}
}

Explanation:
Our app is a node.js app.
It is described by the package.json file
In the package.json file we declare a dependency to the existing default App Router module.

We declare: when our app is started, the javascript file to be executed is the approuter.js, to be found in the existing approuter module
Means, our app does nothing than start the existing approuter, with our configuration

Note:
The version will probably change in future, so make sure to update it, if deployment fails
To update, run npm install --save

Download App Router


Actually, downloading the App Router is not necessary.
The approuter is a node module which will be installed via npm in the cloud environment.
As such, we can just deploy the app, as long as it contains the package.json file which tells how to install and run the approuter.
If it works, you don't need to install node.js on your local machine
If you face dependency errors during deployment, then you need to download/install the approuter module via npm into the application folder, on your local machine.
Only in that case, you need to install node.js on your local machine)

To download approuter, go to command shell, navigate to folder c:\dev\app\approuter
There, execute  the following command:

npm install --save

Deploy the app


Deploy the app to SAP Cloud Platform Cloud Foundry environment, like you’re used to (i.e. command line or cockpit)

Use it


After successful deployment, you have to find the host URL of your app, it is either on the command prompt, or in the app-overview in the cloud cockpit

In my example it is
tobs.cfapps.eu10.hana.ondemand.com

In order to route to our Backend service API, we have to append one of the defined routes (bsv2), followed by the name of our API, as defined in Backend service (in my example PRODUCTSERVICE)
In case of v4 service, we need to add the version parameter(;v=1)

Example URLs:

https://tobs.cfapps.eu10.hana.ondemand.com/bsv2/PRODUCTSERVICE;v=1/
https://tobs.cfapps.eu10.hana.ondemand.com/bsv2/PRODUCTSERVICE;v=1/Products

Other service:

https://tobs.cfapps.eu10.hana.ondemand.com/bsv2/CUSTOMERSERVICE;v=1/

For odata v4, just change the route, e.g.:

https://tobs.cfapps.eu10.hana.ondemand.com/bsv4/PRODUCTSERVICE;v=1/Products

etc

Note:
If you switch from V2 service
https://tobs.cfapps.eu10.hana.ondemand.com/bsv2/PRODUCTSERVICE/
to v4
https://tobs.cfapps.eu10.hana.ondemand.com/bsv4/PRODUCTSERVICE/
you’ll get an error: Invalid URL
The reason is that the version param is required
https://tobs.cfapps.eu10.hana.ondemand.com/bsv4/PRODUCTSERVICE;v=1/

You can execute POST, PATCH, DELETE etc like usual

Even x-csrf-token is not required (at least App Router doesn’t require it and Backend service - currently - either)

Troubleshooting


What to do if you happily deploy everything and try testing and get..... Forbidden ???
See this blog for a Troubleshooting guide

Summary


We want to call our Backend service API from local REST client tool (e.g. Postman)
Instead of fetching OAuth access token, etc, we can do a different approach:

We can app an intermediate App Router in the cloud
That is an app which we have to deploy
That app contains a dependency to the actual App Router which is an existing node.js module
In the app, we configure the App Router such that it redirects to Backend Service
We configure that we can authenticate to our app with "Basic Authentication"
App Router fetches an OAuth access token and forwards it to Backend service

This makes life easier, because now, all APIs can be accessed from REST client without the tedious token-handling

Appendix: XSUAA creation command


If you're using command line, you'll find this copy&paste-ready command helpful.
It creates an instance of XSUAA service, with instance name "XsuaaForAppRouterWithBs"

cf create-service xsuaa application XsuaaForAppRouterWithBs -c "{\"xsappname\":\"XsuaaForAppRouterWithBs\",\"tenant-mode\":\"dedicated\",\"foreign-scope-references\":[\"$XSAPPNAME(application,4bf2d51c-1973-470e-a2bd-9053b761c69c,Backend-service).AllAccess\"]}"
2 Comments