Skip to content

SAP Application Router @sap/approuter

Node.js based application router.

When a business application consists of several different apps (microservices), the SAP Application Router is used to provide a single entry point to that business application

Not part of the SAP Discovery Center!

Almost every application in Cloud Foundry requires an Application Router to authenticate users and dispatch requests to microservices. It needs to be configured and deployed by using the offered @sap/approuter npm package.

SAP Application Router
FeatureDescription
Reverse proxyDispatch requests to backend microservices
UAAAuthenticate users
Static resourcesServe static content

Routes

The following configurations are examples of how to integrate the respective services into the Approuter.

SAP HTML5 App Repository

If using a HTML5 App Repo, generally all unknown requests are forward to it by the last rule:

json
{
    "source": "^(/.*)",
    "target": "$1",
    "service": "html5-apps-repo-rt"
}

The route name of an UI5 app is defined in the manifest.json file:

json
{
	"sap.app": {
		"id": "namespace.app"
        ...
    }
}

The target route name looks like this:

APP_ID = namespaceapp (chars other than [A..Z][0..9] will be removed!)

With this name, you can reference the app behind the approuter out-of-the-box.

Different Route for HTML5 app

If you need a different route (besides above) you have to take care of some specialities! The Repo uses a cache proxy mechanism using ~(.*)~ cache parts, that need to be handled be the route. Also some files should not be cached, so they need a special cache control.

Usage of a custom route ROUTE_NAME for app APP_ID

json
{
    "source": "^/ROUTE_NAME/index.html(.*)$",
    "target": "/APP_ID/index.html$1",
    "service": "html5-apps-repo-rt",
    "cacheControl": "no-cache, no-store, must-revalidate"
},
{
    "source": "^/ROUTE_NAME/sap-ui-cachebuster-info.json(.*)$",
    "target": "/APP_ID/sap-ui-cachebuster-info.json$1",
    "service": "html5-apps-repo-rt",
    "cacheControl": "no-cache, no-store, must-revalidate"
},        
{
    "source": "^/ROUTE_NAME/~(.*)~/(.*)$",
    "target": "/APP_ID/$2",
    "service": "html5-apps-repo-rt"
},
{
    "source": "^/ROUTE_NAME/(.*)$",
    "target": "/APP_ID/$1",
    "service": "html5-apps-repo-rt"
}

UI Theme Designer Runtime

Using a custom theme, an addtional route is nessessary to deliver the endpoint to the com.sap.ui.theming service with the approuter:

json
{
    "source": "^/themes/(.*)$",
    "target": "$1",
    "service": "com.sap.ui.theming",
    "endpoint": "runtime"
}

Standalone SAPUI5 App

Extending

See extending for information how to extend the application router with custom logic.

You can use the application router as a regular Node.js package. Insead of starting the application router directly, your application can have its own start script:

approuter.js

js
var approuter = require('@sap/approuter');

var ar = approuter();
ar.start({
  extensions: [
    require('./my-ext.js')
  ]
});

Implement the addtional logic in custiom middlewares:

my-ext.js

js
'use strict';
const jwtDecode = require('jwt-decode')

module.exports = {
    insertMiddleware: {
        first: []
        beforeRequestHandler: [
            {
                path: '/',
                handler: function forwardUserInfo(req, res, next) {
                    res.setHeader('x-authenticated', !!req.user)
                    next()
                }
            },
            {
                path: '/me',
                handler: function getUserInfo(req, res, next) {
                    if (!req.user) {
                        res.statusCode = 403;
                        res.end('Missing JWT Token');
                    } else {
                        const { user } = req
                        const token = 
                            jwtDecode(user.token.accessToken);
                        res.statusCode = 200;
                        res.setHeader('Content-type", 
                            'application/json');
                        res.setHeader('Cache-Control', 
                            'no-cache, no-store');
                        res.end(JSON.stringify({
                            'id': user.id,
                            'loginName': user.id,
                            'firstName': token.given_name,
                            'lastName': token.family_name,
                            'email': token.email,
                            'roles': token['xs.system.attributes']
                                ['xs.rolecollections'],
                            'sessionTimeout': 
                                req.routerConfig.sessionTimeout
                        }));
                    }
                }
            },
        ],
        afterRequestHandler: []
    }
};

Support

Component NameComponent Description
BC-XS-APRSupport component for this service