This SAP Tech Byte is about how to use the Destination Service on Cloud Foundry and consume destinations using a node.js based approuter.
The source code for this blog post can be found on https://github.com/SAP-samples/sap-tech-bytes/tree/cloud-foundry-basics/post3.
Building on top of the
previous blog post of this "Cloud Foundry Basics" series, where we learned how to serve a web page using a standalone approuter, we will use this approuter to consume data through a destination instance of the Destination Service on the SAP Business Technology Platform, Cloud Foundry environment today.
Current State of the Application
This is what the application currently looks like:
It is a node.js based application router deployed to Cloud Foundry, that is serving an
index.html file, where we added some UI elements in the form of UI5 controls. The approuter is bound to an instance of the Authorization and Trust Management Service (xsuaa) in Cloud Foundry. This allows us to call the
/user-api/currentUser endpoint and get information about the logged in user. All of this routing configuration is defined in the
xs-app.json file:
{
"welcomeFile": "index.html",
"authenticationMethod": "route",
"routes": [
{
"source": "^/user-api(.*)",
"target": "$1",
"service": "sap-approuter-userapi"
},
{
"source": "^(.*)$",
"target": "$1",
"authenticationType": "xsuaa",
"localDir": "./"
}
]
}
Adding a New Route
We will now extend this
xs-app.json file with a new
"^/backend(.*)" route. We want the approuter to forward all requests that hit that route to the destination that will be bound to the application. We therefore add a new route to the
xs-app.json file as the second route in the array, before the
"^(.*)$" route. The order of the routes does matter, because the approuter compares the requests and routes from top to bottom and will select the route that matches first.
{
"welcomeFile": "index.html",
"authenticationMethod": "route",
"routes": [
{
"source": "^/user-api(.*)",
"target": "$1",
"service": "sap-approuter-userapi"
},
{
"source": "^/backend(.*)",
"target": "$1",
"destination": "backendDestination",
"authenticationType": "none"
},
{
"source": "^(.*)$",
"target": "$1",
"authenticationType": "xsuaa",
"localDir": "./"
}
]
}
The regular expression
"^/backend(.*)" will also match requests such as
/backend/Products, so we will be able to request specific recourse from that API.
In case you are wondering why
"target": "$1" is included in all the routes: It means that the target of the request will be the first capture group that matches the regular expression of the route. If we send a request
/backend/Products, the first capture group that matches the
"^/backend(.*)" regular expression is
/Products, leaving us with
"target": "/Products", which will be attached to the destination. Essentially, it makes sure that the word "backend", which is just a placeholder for us, will not actually be sent to the destination.
Creating the Destination
Next, we want to create an instance of the Destination Service in Cloud Foundry. We will use the Cloud Foundry CLI in this case, but you could achieve the same thing using SAP BTP Cockpit.
First, we create a configuration file that holds the information about the destination (more info in the official
documentation). We create the following
dest-config.json file:
{
"init_data": {
"instance": {
"existing_destinations_policy": "update",
"destinations": [
{
"Name": "backendDestination",
"Authentication": "NoAuthentication",
"ProxyType": "Internet",
"Type": "HTTP",
"URL": "https://services.odata.org/V4/Northwind/Northwind.svc/"
}
]
}
}
}
Notice how the name of the destination matches the name we specified for the route in the
xs-app.json of the approuter - this is very important. For the URL we specified the popular Northwind OData service, but feel free to replace this with any other REST based API you want to consume (
What is REST?).
We can now go ahead and create an instance of the Destination Service using this configuration. Make sure to be logged in to your Cloud Foundry environment. We execute the following command to create the instance by specifying a service, service plan, instance name and configuration file:
cf create-service destination lite backendDestination -c dest-config.json
Binding the Application to the Destination Instance
We want to extend our manifest.yaml file so that our application will be automatically bound to the backendDestination instance during deployment. We add the service instance to the services section of the file, so it looks like this:
---
applications:
- name: my-web-page
buildpack: https://github.com/cloudfoundry/nodejs-buildpack
random-route: true
services:
- my-xsuaa
- backendDestination
We also added the "random-route: true" attribute to the configuration, which will make sure our application will have a unique URL. Someone else might have already deployed an application called "my-web-page" your region and we want to avoid conflicts.
Deploying and Testing Application
We can now go ahead and deploy the application using the
cf push command, just like we did in the
previous post. In the terminal output, we will get the URL (route) to our application:
When visiting the URL, we don't see any visible changes compared to the previous post, which is fine, since we did not touch the UI at all. The new feature we implemented unveils itself if we attach our /backend route to the URL of our application:
The approuter forwards the
/backend request to the Northwind OData service and sends the response back to our application. We can see the Northwind service, but looking at the URL it appears as if is "part of our application". This is very important considering the
CORS policy of modern browsers. Probably every web developer has encountered this problem at least once, and this is one way to solve it.
We can also try and request specific entities of the Northwind service such as
/Products, which also works:
And that's it. We can now use our approuter to consume data from an external API using the Destination Service in Cloud Foundry. We can simply call a relative URL (
/backend/Products) from the application to get the data.
Check out the
next blog post of this series.
Feel free to reach out in case you have any questions.
Stay tuned for more blog posts covering the basics of Cloud Foundry.
SAP Tech Bytes is an initiative to bring you bite-sized information on all manner of topics, in
video and
written format. Enjoy!