Technical Articles
Consume External Service using Application Router
In my previous blog posts:
I discussed about consuming external service within the backend service using Cloud Application Programming (CAP) Model. This is the approach you need to use if you need to process the data or do some manipulation before you provide the data to your consumer application.
But what if you don’t need to process the data? Instead, you want to use the data directly in your web application!
In this blog post, I will show the setup on how to consume a destination configuration from a Cloud Foundry Destination Service via the App Router module.
Use Cases
- Consumption of external services (non-SAP systems)
- Consumption of external services from S/4HANA Cloud
- Consumption of external services from on-premise SAP systems
Note: Consumption of external services from on-premise requires: (1) Connectivity Service and (2) SAP Cloud Connector setup which will not be covered in this blog post. |
Prerequisites
- SAP Cloud Platform Account
- SAP Business Application Studio / Visual Studio Code
Setup Destination Configuration
For the destination configuration, we will be using the popular NorthWind service:
https://services.odata.org/Experimental/OData/OData.svc/
For the setup of destination in SCP Cloud Foundry, I have already discussed this in detail in my previous blog post:
CAP Consume External Service – Part 2
So go ahead and refer to that post specifically in the Setup Destination Configuration section and come back to this blog post once you’re done with the setup.
Create the MTA Project
It’s now time to create our MTA Project! For this case, it’s not necessary to create a CAP Model project. This is actually applicable whether you are using CAP Model or not.
- 1. The mta.yaml file configuration:
_schema-version: "3.1"
ID: demo.approuter
version: 0.0.1
description: "Demo on consuming destination service via app router"
parameters:
enable-parallel-deployments: true
modules:
- name: demo-app-router
type: approuter.nodejs
path: app-router
parameters:
disk-quota: 256M
memory: 256M
requires:
- name: demo-destination
- name: demo-uaa
resources:
- name: demo-uaa
type: org.cloudfoundry.managed-service
parameters:
path: ./xs-security.json
service-plan: application
service: xsuaa
- name: demo-destination
type: org.cloudfoundry.existing-service
In the resources section, we need to configure our UAA service because this is required by the destination service. Another configuration is for our destination service where we configured the NorthWind destination.
In the modules section, we defined our app-router module where we make use of our destination and UAA service.
- 2. Creating the app-router module from scratch is very simple, we just need to setup our package.json as below:
{
"name": "app-router",
"description": "Node.js based application router service",
"engines": {
"node": "^8.0.0 || ^10.0.0"
},
"dependencies": {
"@sap/approuter": "6.8.0"
},
"scripts": {
"start": "node node_modules/@sap/approuter/approuter.js"
}
}
Make sure that you create this file under the app-router folder because this is how our mta.yaml is setup.
- 3. The app-router module needs to have the routing configuration inside the file xs-app.json:
{
"authenticationMethod": "route",
"routes": [{
"source": "/Experimental/OData/OData.svc/(.*)",
"target": "$1",
"destination": "NorthWind"
}]
}
In this routing configuration, we take any queries from path /Experimental/OData/OData.svc/ and redirect it to our NorthWind destination. This is as simple as it can get for our basic routing configuration demo.
Note: If the external service is using HTTP methods that is protected by X-CSRF Token, then your routing configuration should have additional setting below:
this is to bypass the built-in csrf token handling of the application router. |
- 4. Setup the basic xsuaa security configuration in file xs-security.json (this should be in the root folder of our project):
{
"xsappname": "demo-uaa",
"tenant-mode": "dedicated",
"description": "Security profile of called application",
"role-templates": [
{
"name": "Token_Exchange",
"description": "UAA",
"scope-references": [
"uaa.user"
]
}
]
}
Note that all users of the UAA service requires the uaa.user scope, and this is why we have this configured in here.
At this point, our MTA project should have a structure like the screenshot below:
- 5. The last step, of course, is to build and deploy this project to SCP Cloud Foundry. For this demo, I’m using a cloud foundry trial account.
Test the App Router service
- 1. After successfully deploying the app router to SCP Cloud Foundry, test the service by calling the app-router service with below path using your favourite web browser:
<app-router-hostname>/Experimental/OData/OData.svc/Products
By seeing the data returned by the app-router service, we can conclude that we are able to connect to the destination service and make use of the configured NorthWind destination.
Closing
Now you see how easy it is to setup a destination using the SCP Cloud Foundry destination service and consume it using Application Router. This external service can then be fed into a UI5 application that is hosted in SCP. This is usually the case for a side-by-side extension of an SAP delivered solution.
Please do take note that the setup is a simple configuration of an external service that doesn’t require a username and password credentials. Most services that you will probably encounter have basic authentication security and this can be easily setup in the destination service just by choosing the Basic Authentication from the dropdown list and then provide the username and password.
Another thing to note here is that, if the source external service is from an on-premise environment like S/4HANA, you need to setup an SAP Cloud Connector and Connectivity Service in order for you to be able to connect to that on-premise web service.
~~~~~~~~~~~~~~~~
Appreciate it if you have any comments, suggestions, or questions. Cheers!~
Again, a nice blog, I followed it through, thanks!
Thanks Chunyang! 😀
Dear Jhodel,
Thanks for the nice blog.
I am following the same to connect to a Gateway based service from SAP HANA System.
I am getting error - PERSISTENCE_SKIP_NO_GENERIC_CRUD while triggering read request on external service. ( I have raised separate query - https://answers.sap.com/questions/13196077/error-persistence-skip-no-generic-crud-while-readi.html for the same )
To give you a brief, my Node js based CAP service is deployed in XSA On-Premise system and we are accessing the CAP service directly without using AppRouter.
I am able to follow your blog - other than the destination configuration which you did in mta.yaml file.
Could you please help me out here.
Best Regards,
Shyam Vasani
Hi Jhodel,
Thumps up to all your blogs. Quite informative.
With the above approach when I am trying to connect to an On-Prem destination it gives the below error:
"Service completed with status 500 - Destination \"<Name>\" with ProxyType \"OnPremise\" but connectivity service is not bound"
Whereas I have bound the connectivity service instance under Service Bindings.
What could be the probable issue. Please suggest if you have come across similar issue.
Thanks
Shyam
Hi shyam singh, thanks for your comment!
Based on the error you got, it seems that the connectivity service is not bound to app router. You need to make sure that it is bound in order for the on-premise service consumption to work. Or maybe there's some other underlying root cause that is related to how you created the connectivity service in your BTP.
Hi Shyam,
facing same issue. Did you solve this problem: "but connectivity service is not bound"?
The connectivity service is already bound to approuter
Regards
Baris
Hello Jhodel,
Thanks for such an amazing blog. This is exactly the info I needed 🙂 ( Consumption of an external service using the Approuter on top )
I had two questions to your blog.
You mention that this approach can be used for the side-by-side extension scenario.
a) As I was imagining this approach ( with an on-premise SAP System and BTP), I thought there could be one single Approuter CAP Application ( created like you explained above) that would just expose all the backend services using different Routes. Since the authentication is at a route level, each route can have its own authorizations.There would be a single Destination configured in the account which would point to the On-Premise System. And ofcourse the cloud connector would also be in place.
Once all the needed backend OData services have been exposed in this way, they can then be consumed by further extension CAP / Fiori / UI5 Applications as needed. Is this what you had in mind when you mentioned the side-by-side scenario ?
b) The process of consuming an external service within a CAP Application is clear ( as explained in your other blog - CAP: Consume External Service Part 1 and 2 ). It involves the creation of a Destination . However, when we create an extension CAP / FIori / UI5 Application for a side-by-side scenario, we would not be consuming an On-Premise or External Service. Instead we would be consuming the cloud-foundry-hosted service offered by the Approuter CAP Application (what we created in this blog).
My question is how does one consume the Approuter CAP Service that we created above , in another extension CAP Application?
I believe I could always hardcode the URL of the Approuter CAP Service in the cds.requires.credentials.url property of the extension CAP Application. But this doesn't seem elegant. Is there some other approach that can be considered here ?
Once again , many thanks for your awesome work.
Regards
Shadab Alam.
Nice tutorial. Thanks alot.
I try to consume an external Odata with an app that I have deployed using the managed app router of the launchpad service. The routing is defined in the xs-app.json but it doen't work.
Setting up a demo implementation in SAP BAS with the routing defined in ui5.yaml works perfectly. So the destination setup and the cloud connector are working.
It seems the launchpad app router does not use the routing setup I provided. Do I need to setup something else to make the managed approuter use the routing setup?
Thanks for the comment Stephan Smola !
Unfortunately, I haven't really used the Launchpad service, so I can't comment on that.