Technical Articles
How to consume on-prem services in public Node.JS API deployed on Cloud Foundry
Introduction
I wanted to create some public API with Node.JS which needs to deploy on Cloud foundry environment. In that I had to consume on-prem service. While consuming on-prem service in unauthenticate Node.JS app, throwing me error as Invaild Proxy Authorization Header. After lot of search, I figure out the solution for it. So I’m thinking to write solution in one place.
In this blog post will explain you how to connect with on-prem services with Node.JS using XSUAA & Connectivity service instances.
Coding
- Create package.json file & update with it below code
{ "name": "<APP_NAME>", "version": "1.0.0", "description": "", "main": "app.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "node app.js" }, "author": "Prashant Patil", "license": "ISC", "dependencies": { "@sap/xsenv": "^2.2.0", "body-parser": "^1.19.0", "express": "^4.16.4", "request": "^2.88.0", "request-promise": "^4.2.5" } }
- Create manifest.yml file & update with below code
--- applications: - name: test-app memory: 128M instances: 1 services: - test-app-uaa - test-app-conn
- Create service instances mentioned in manifest.yml using CF CLI
cf create-service xsuaa application test-app-uaa
cf create-service connectivity lite test-app-conn
- Create app.js & paste below code, We are going connect to the on-prem service through connectivity service instance.
const express = require('express'); const rp = require('request-promise'); const xsenv = require('@sap/xsenv'); //For local run //xsenv.loadEnv(); const http = require('http'); var bodyParser = require('body-parser'); const app = express(); var server = http.createServer(app); const port = process.env.PORT || 3000; var jsonParser = bodyParser.json(); var urlencodedParser = bodyParser.urlencoded({ extended: false }); const conn_service = xsenv.getServices({ conn: { tag: 'connectivity' } }).conn; const uaa_service = xsenv.getServices({ uaa: { tag: 'xsuaa' } }).uaa; const sUaaCredentials = conn_service.clientid + ':' + conn_service.clientsecret; const proxy_url = 'http://'+conn_service["onpremise_proxy_host"] + ':' + conn_service["onpremise_proxy_port"]; const onPremCred = '<OnpremSrvUser>:<OnpremSrvUserPassword>'; server.listen(port, () => console.log(`test app listening at http://localhost:${port}`)); app.post('/getDetailsFromOnPrem',jsonParser , (req, res) => { return rp({ uri: uaa_service.url + '/oauth/token', method: 'POST', headers: { 'Authorization': 'Basic ' + Buffer.from(sUaaCredentials).toString('base64'), 'Content-type': 'application/x-www-form-urlencoded' }, form: { 'client_id': conn_service.clientid, 'grant_type': 'client_credentials' } }).then((data) => { const token = JSON.parse(data).access_token; return rp({ uri: '<on-prem service url>', proxy:proxy_url, headers : { 'Authorization': 'Basic ' + Buffer.from(onPremCred).toString('base64'), 'Proxy-Authorization': 'Bearer ' + token, 'SAP-Connectivity-SCC-Location_ID':'<Cloud-Connector-Location-Id>', 'Content-type': 'application/json' } }); }).then((data) => { const d = JSON.parse(data); res.send(d); }).catch((error) => { res.send(error); });
- Deploy app to CF
cf push test-app
Note:
if you have only one connector without location Id (default) in your sub-account, then do not provide ‘SAP-Connectivity-SCC-Location_ID’ as header.
If you have multiple Cloud connectors added in your sub-account then ‘SAP-Connectivity-SCC-Location_ID’ header is must else it will trying connect with default cloud connector.
Conclusion
In this blog post you learned how to consume on-premise services in unauthenticated Node.JS app deployed on CF.
Hope this helps!
Prashant Patil
Hi Prashant Patil ,
With the same approach i am getting 'Invalid protocol: undefined', can you advise on the below?
Hi Ramon,
is your on-prem service reachable directly?
All code looks ok to me.
Regards,
Prashant
Hello ,
I HAVE THE SAME PROBLEM. error Invalid protocol: undefined
connectivityproxy.internal.cf.xxxxx.hana.ondemand.com 20003
HOW DID YOU SOLVE IT?
Regards,
Diego