Skip to Content
Technical Articles

SAP Approuter – User API Service

Hi Community,

What is an app without a logged in user to roam around an consume your services?

Nothing, exactly!

But when we finally have our logged in user to use the app, we also want to display his/her user information.

Which could be done like the example below for instance:

Above example is a combination of the following two UI5 controls:

An SAPUI5 Tool Header: Samples – Demo Kit – SAPUI5 SDK (ondemand.com)

An SAPUI5 Avatar: Samples – Demo Kit – SAPUI5 SDK (ondemand.com)

Back then on the SAP Cloud Platform NEO Environment, there was the possibility to consume the “userapi” service by adding a route to the “neo-app.json” file. This allowed the developer to retrieve the current logged in user information such as name, firstName, lastName, displayName and email.

But then a new era arose, the SAP Cloud Platform Cloud Foundry Environment era. Which brought so many possibilities with it, that developing became even more fun! But there was one small catch bound to this Cloud Foundry Environment. We developers lost our NEO “userapi” … But we always find a solution for everything and very often they are shared on the SAP Community. But it meant that an alternative with some custom developments were required to retrieve the necessary information.

Some solutions shared by the SAP Community members to retrieve the current logged in user information can be found here:

But like we all grow in our development skills, the technologies and features do too.

The SAP Approuter NPM Package was extended with a “User API Service”.

All required information and more about this service can be found here:

@sap/approuter – npm (npmjs.com)

This also means there is no need to describe this “Approuter User API Service” further in this blog post.

But we can build a very small and quick demo app together!

Let’s open the SAP Business Application studio!

 

Consuming the SAP Approuter – User API Service

Open a terminal in your BAS development workspace and execute the following command to initialize a basic multitarget application:

yo basic-multitarget-application

Name the project “approuterUserInformation”.

This generated your project, which is quite empty at the moment:

Enter the project by executing the following command and create an “approuter” directory and access it as well:

cd approuterUserInformation && mkdir approuter && cd approuter

Inside this “approuter” directory we execute the following command to initialize npm:

npm init

Just use the default values for the configuration of the command above.

Once generated add the “start” script inside your “package.json” file so it looks like this:

"start": "node node_modules/@sap/approuter/approuter.js"

Finally, we install the SAP Approuter NPM package by executing the following command:

npm i @sap/approuter

If I’m not mistaken the SAP Approuter User API Service is available since version “9.1.0”.

Create an “xs-app.json” file by executing the following command:

touch xs-app.json

Add the following configuration to it:

{
    "welcomeFile": "index.html",
    "authenticationMethod": "route",
    "routes": [
        {
            "source": "^/user-api(.*)",
            "target": "$1",
            "service": "sap-approuter-userapi"
        }
    ]
}

As you can see the route will consume the “sap-approuter-userapi” service to return the logged in user information. Do note the “authenticationMethod” property is set to “route” so authentication is enabled for the desired routes.

The “source” uses the following regex “”^/user-api(.*)” which should be completed in either one of the following ways to retrieve the user information:

  • /currentUser
  • /attributes

Both endpoints return firstName, lastName, email and name. While the “/currentUser” endpoint also returns the displayName.

Running the Approuter and requesting the endpoint in one of the two ways described above would not work.

It would return the following error:

“GET request to /user-api/currentUser completed with status 500 OAuth2 requires “clientid” option.”

The reason for that is because we are still missing an “xsuaa” service instance.

Login to Cloud Foundry via the Business Application Studio or by using the BAS terminal cf cli.

Next you create an “xsuaa” service instance via the BAS command pallet (CTRL + Shift + P) and you type “create a new service instance” (choose a name for the “xsuaa” service instance with the “application” service plan) or by using the cf cli on the terminal, or even via the SCP Cockpit.

Once created, you bind the “xsuaa” configuration via the command pallet “bind a service to locally run application”, choose your “approuter” directory as destination and you will see a “.env” file will be created. Rename the “.env” file to “default-env.json” and correct the JSON content. Or use the terminal achieve the same result.

You will need the “default-env.json” file holding your “xsuaa” service configuration to be able to perform authenticated requests.

Time to run your Approuter by executing the following command:

npm run start

Remove the “/index.html” part of the URL and type the following like configured in the Approuter:

/user-api/currentUser

As you can see you get the expected response:

{
  "firstname": "Dries",
  "lastname": "Van Vaerenbergh",
  "email": "myEmailAddress",
  "name": "myEmailAddress ",
  "displayName": "Dries Van Vaerenbergh (myEmailAddress)"
}

Now try the attributes URL-endpoint:

/user-api/attributes

Once more we receive the desired response from our Approuter its User API Service:

{
  "firstname": "Dries",
  "lastname": "Van Vaerenbergh",
  "email": "myEmailAddress ",
  "name": "myEmailAddress "
}

 

Wrap up

Like I mentioned before it was very easy to use the “userapi” on the NEO Environment, and we had some extra developments to achieve the same result in the Cloud Foundry Environment.

But now with this SAP Approuter upgrade we only need our “xsuaa” service instance and the right Approuter version and configuration, so we can easily consume the desired user information inside our applications.

I hope this can ease your developments and needs to retrieve the logged-on user information.

Best regards,

Dries Van Vaerenbergh

23 Comments
You must be Logged on to comment or reply to a post.
    • Thanks a lot Yogananda!

      It's a pleasure to share!

      A really nice functionality of the SAP Approuter, it will really simplify the development process to retrieve the user information a lot.

      Best regards,

      Dries

  • Hi Dries,

     

    Thanks. This is a very useful addition to the @sap/approuter indeed!
    Have you tried running this locally with VCAP_SERVICES loaded for xsuaa via default-env.json? I'm getting a 503, while it's working without any issues in CF.

     

    Pieter

    • Hi Pieter,

      Thanks a lot!

      I just tried it myself locally with VS Code and it seems to work.

      The only thing I changed was the xsuaa service instance. I recreated this instance and added the "http://localhost:5000" to the "redirect-uris" in the configuration steps of the xsuaa.

      Further my "package.json" file looks as follow with version "9.1.0" for the approuter:

      {
        "name": "approuter",
        "version": "1.0.0",
        "description": "",
        "main": "index.js",
        "scripts": {
          "test": "echo \"Error: no test specified\" && exit 1",
          "start": "node node_modules/@sap/approuter/approuter.js"
        },
        "author": "",
        "license": "ISC",
        "dependencies": {
          "@sap/approuter": "^9.1.0"
        }
      }
      

      And the "xs-app.json" file like this:

      {
          "welcomeFile": "index.html",
          "authenticationMethod": "route",
          "routes": [
              {
                  "source": "^/user-api(.*)",
                  "target": "$1",
                  "service": "sap-approuter-userapi"
              }
          ]
      }

      And the "default-env.json" file looks like this:

      {
          "VCAP_SERVICES": {
              "xsuaa": [
                  {
                      "name": "xsuaa-approuter-local",
                      "instance_name": "xsuaa-approuter-local",
                      "label": "xsuaa",
                      "tags": [
                          "xsuaa",
                          "endpoint:",
                          "org:",
                          "space:"
                      ],
                      "plan": "application",
                      "credentials": {
                          "apiurl": "",
                          "clientid": "",
                          "clientsecret": "",
                          "identityzone": "",
                          "identityzoneid": "",
                          "sburl": "",
                          "service_key_name": "",
                          "subaccountid": "",
                          "tenantid": "",
                          "tenantmode": "",
                          "uaadomain": "",
                          "url": "",
                          "verificationkey": "",
                          "xsappname": "",
                          "zoneid": ""
                      }
                  }
              ]
          }
      }

      Once my approuter is started I perform the following request and I retrieve the user information:

      http://localhost:5000/user-api/currentUser

      Did you perform all of these steps as well?

      Best regards,

      Dries

       

      • Hi Dries,

         

        Thanks for pointing out "redirect-uris". Unfortunately I'm not out of the woods yet.

        I removed all other routes, just to make sure there are no conflicts.

        I'm now seeing errors that indicate it's trying to resolve the path in a localDir, which is clearly not set.

        #2.0#2021 01 29 10:15:26:026#+01:00#ERROR#/Handler#####kki2mfuv####6YNMkqgp1QWBar-rm5zEmvihtzMVbkQy######kki2mfuv#PLAIN##GET request to //currentUser completed with status 404 ENOENT: no such file or directory, stat '/mnt/c/Users/pietejanssens/code/approuter/resources/currentUser'#

        I put a breakpoing in .node_modules/@sap/approuter/lib/middleware/user-api-middleware.js and when I go to 'http://localhost:5000/user-api/currentUser' it does break and I see that 'req.internalUrl.route.service' is undefined! 🤯

        I don't see any errors in my xs-app.json and the service is correctly set (otherwise it wouldn't work in CF either):

        {
            "welcomeFile": "/router/index.html",
            "authenticationMethod": "route",
            "logout": {
                "logoutEndpoint": "/do/logout"
            },
            "routes": [
        
                {
                    "source": "^/user-api(.*)",
                    "target": "$1",
                    "service": "sap-approuter-userapi"
                }
            ]
        }
        • After further investigation I see that this issue is introduced as soon as I put a

          html5-apps-repo in the VCAP_SERVICES of default-env.json. 🤔
          I'll create an incident for that.
          • Hi Pieter,

            From your shared "xs-app.json" configuration and your last comment, I can tell you are adding this feature in an existing project or you are try out some extra stuff. When you try the example exactly like in the blogpost I believe it does work right?

            If you try to set the "welcomeFile" property to "index.html" and you remove the "html5-apps-repo" from your "default-env.json" file, does it work then?

            I also used the "html5-apps-repo" before in my VCAP_SERVICES in my default-env.json file. I believe that should still work actually, you can find an example here

            Timesheet Management with CAP & Trello ⏱️ – Setup the IDE & MTA Project #1 | SAP Blogs

            I suggest you try without the "html5-apps-repo" first and with the "index.html" as "welcomeFile" value.

            Hope that will get it up and running. 🙂

            Best regards,

            Dries

          • Hi Pieter,

            Good to hear it works that way!

            Curious as I am I tried it out myself using the "html5-apps-repo" and it works perfectly indeed once deployed to CF. I also experienced the same issue (using BAS) when trying to use the "html5-apps-repo" to run it locally (after binding it in the default-env.json file). I also get the "503 service unavailable" when requesting the user information in this case. using localDir it works fine when requesting the information from the ui5 app via the approuter. Maybe Marius Obert has an idea about this one? 🙂

            Still an amazing update to the SAP approuter and a handy to use service of course.

            Best regards,

            Dries

          • I have to admit you are already way deeper in this than I am 🙂

            I'd suggest opening a new question for this in the community so that the product team can pick it up.

          • SAP (Sergio):

            This flow will work if instead of using defaut-env.json you would set the VCAP_SERVICES as IDE environment variable. With this it is guaranteed that the node process environment is correctly populated before start.

            This is a limitation of providing environment variables via files. Currently there is no correction that we can provide.

            Root cause:

            1. During approuter startup DynamicRouting middleware is initialized if approuter is bound to html5 repo. This check returns false because xsenv module does not find default-env.json in the disk because the app. is not started yet, therefore the middleware is not initialized

            2. Later on, during path evaluation, binding to repo is evaluated again and it returns true, but this is too late because the DynamicRouting middleware was not loaded and this is a kind of inconsistent state.

    • Haha nice one Marius Obert !

      I really like the way the Community shares its solutions and that we can all benefit from each others ideas and visions. Thanks to everyones contribution the circle of amazing ideas keeps going!

      So a big thanks to everyone for the solutions and inspiring ideas! 😃

    • Hi Pablo,

      Thanks for your question.

      I am not sure if I understand your question correctly but if you mean an "xs-app.json" file by app router file, a Fiori/HTML Module contains an "xs-app.json" file as well.

      But by adding the route with the User API service to the Fiori Module its "xs-app.json" file, I do not believe this will work, since this User API service is an SAP Approuter feature.

      But when you generate a new project (for example via the wizard in the SAP BAS) you have to choose an approuter (standalone or managed) and thus you are able to implement such a scenario to consume the user information via the approuter.

      I hope this answers your question.

      Best regards,

      Dries

    • Hi Pablo,

      Yes. It should work both with xs-app.json on application level or on approuter level.

      It means that you will be able to use it also when working with managed approuter.

      Best Regards,

      Ari

      • Hi Ari,

        Thanks for your answer!

        Implementing the following route on approuter level (xs-app.json) does work indeed (with xsuaa bound of course and authenticationMethod route):

        {
                    "source": "^/user-api(.*)",
                    "target": "$1",
                    "service": "sap-approuter-userapi"
                }

        But when using the exact same route and xsuaa service on application level the app won't start. I'm using the BAS with a basic UI5 app from template and a managed approuter.

        So I was not able to use the User API Service on the application level yet.

        Any Idea on this one? Did you experience a different result?

        Thanks in advance!

        Best regards,

        Dries

        • Hi Dries,

          You were too quick with your blog 🙂

          It will be supported in Managed Approuter next week.

          That's the reason Managed Approuter docs were not updated yet:

          https://help.sap.com/viewer/8c8e1958338140699bd4811b37b82ece/Cloud/en-US/c1b9d6facfc942e3bca664ae06387e9b.html

          Once it will be supported, also a release note will be published.

          Best Regards,
          Ari