Technical Articles
Split MTA into backend & frontend – Standalone AppRouter
In my previous blog post, I shared how you can split the backend from the frontend in an MTA project by using the managed AppRouter:
https://blogs.sap.com/2021/03/03/split-mta-into-backend-frontend-managed-approuter/
Now, it could be possible that you don’t have the possibility to use the Managed Approuter. This is part of the Launchpad/Portal Service in CloudFoundry which you maybe do not have. Paying the license for this service, only for the managed AppRouter, would not make sense and overpriced 😊. As solution to this, you could just use the standalone AppRouter. Using the standalone AppRouter gives you also another way of splitting up your mta into backend and frontend. Because we have full control of the standalone AppRouter, we can use Cross-MTA dependencies.
Compared to the managed AppRouter you can split up into three parts with the standalone AppRouter:
- AppRouter
- Frontend: One or more UI5 apps using the HTML5 App Repo
- Backend: CAP Project with API and HDB layer
One AppRouter can handle navigation to multiple apps. Therefore, I decided to put this into a separated MTA as well. Depending on how intensively your apps are being consumed or different configuration requirements for your apps it could be useful to have more than one (It all depends on the use case.). For me, one would do the job.
Before explaining the steps to achieve this, I want to provide additional information on how everything will be connected. The standalone AppRouter will be the single point of access to the frontend and the backend. The AppRouter will forward requests to the backend or the frontend based on the route configuration. Take for example the route “/browse” or “/v2/browse” which is connected to the destination of the backend, in this case the approuter will forward the request to the backend. Any other path will be forwarded to the html5 app repo.
Every MTA requires configuration to make this work:
- The backend has to make the provided service url public to other mta’s
- AppRouter must consume the service url as resource in the MTA configuration
- Approuter will access all the UI5 apps from HTML5 App Repo service
- HTML5 App Repo should contain the route configuration (xs-app.json)
- The destination to the service in the HTML5 app Repo will be known in the Approuter because of the Cross-MTA Dependencies configuration.
In the next following sections, I’m going to focus on how every step can be implemented.
MTA Backend – CAP project with API and HDB layer
For starting, I generated a CAP project by using VSCode with the following steps:
https://cap.cloud.sap/docs/get-started/in-a-nutshell
Followed by this one to have the MTA configuration:
https://cap.cloud.sap/docs/advanced/deploy-to-cloud#deploy-using-mta
This can also be done using the SAP Business Application Studio.
Besides defining the database and service, only one thing needs to change here. The provided binding with the service url in the MTA configuration needs to be “public”. This can be done by adding “public: true” in the service binding:
The full project can be found on GitHub: https://github.com/lemaiwo/SCP-CF-DemoApp/tree/master/DemoService
MTA – Standalone AppRouter
For this I created an empty mta project and added the module manually. You can also try the new generator for this in the SAP Business Application Studio.
The frontend app, which contains the routes, will be loaded via the Standalone AppRouter. Therefore, the standalone AppRouter needs to known the destinations defined in the xs-app.json of the frontend app.
This can be done by using Cross-MTA Dependencies:
- Add the service binding as a resource to the MTA
- This contains configuration that refers to the MTA of the backend CAP project and provided binding.
- Use the resource in the “requires” section of the approuter module
- This configuration will use the service url from the service binding to define the “srv_api” destination. (This is very similar in case we use one MTA for all modules)
Next to that, the CAP service and the approuter need to use the same XSUAA instance. This requires that both use the same “xsappname” in xs-security.json. Another solution could be to use “existing-service” instead of “managed-service” in the xsuaa definition in the resources section.
The mta project can be found on GitHub: https://github.com/lemaiwo/SCP-CF-DemoApp/tree/master/AppRouterOnly
MTA Frontend – HTML5 app repo
For generating this MTA project, you can use the Fiori generator in Business Application Studio or VSCode. For VSCode, you can try following this blog: https://blogs.sap.com/2021/01/12/ui5-freestyle-generator-wizard-in-vscode/
The frontend app is the place to define the routes to the backend in the xs-app.json. This configuration will be retrieved by the AppRouter. Routes to the backend need to have the same name for the destination as the name in the mta config of the AppRouter. This is why the AppRouter requires the binding to the service url in the MTA configuration.
The frontend app doesn’t need to have the same xsuaa service which allows to have its own “xsappname” in xs-security file.
The mta project can be found on GitHub: https://github.com/lemaiwo/SCP-CF-DemoApp/tree/master/AppOnly
Wrap-up
Deploy all MTA projects and you are done! 🙂
Compared to my previous blog post about splitting up the MTA into frontend and backend, I now showed how to do this with a standalone AppRouter and using Cross-MTA Dependencies.
This time I ended up with three MTA projects, one for the frontend, one for the backend and finally one for the standalone AppRouter. Every MTA projects requires a small part of configuration to connect them all together. The app can now run as one end-to-end application with each module its own lifecycle.
The GitHub repository with all different MTA projects can be found here: https://github.com/lemaiwo/SCP-CF-DemoApp
Is it also possible to share that "central" application router by applications across multiple spaces (in the same subaccount)?
Normally I use for that case SaaS approuter from Launchpad, but that custom shared approuter would give me more control
The cross-mta dependencies can be used across spaces, you have to change the spacenamr in the mta config of the approuter.
But the approuter and service require the same xsuaa instance. So not immediately sure how this can be handled across spaces..
Hmm, so that seems that its not possible right now 🙁 Until SaaS XSUAA will be provided.
But thank for a interesting blog. Your blogs always broadens my knowledge a bit further.
Informative
Hi, Thanks for this amazing blog !
I'm a newbie and trying to explore mta in cf. I have two questions - 1. Apart from using launchpad service, is there any other way to access the ui5 application stored in html5-repo instance? 2. Is it necessary to link a destination instance to a html5-application-runtime in order to view it at some route?
Thanks
1) yes, you have a menu item “HTML5 Application” . You will find a list of all html5 apps
2) yes
Hi Wouter Lemaire
Thanks for a great post.
I just have a quick question: How do we expose CAP service as a destination so we can use BAS UI5 wizard template to generate the project? I've tried to set up destination with different oauth2 authentications but it keeps asking for service username and service password.
It seems working with SAP WebIDE.
Regards,
Tri
Can you try changing data source to local CAP service? Otherwise, I'm not sure how to do this...
Hi Wouter Lemaire,
Thanks for this great Blog.
I have a small question, In my case I have a single app repo having ui5 apps, app-router, and Nodejs cap service. I want to split it in such a way that I have only 2 repos .i.e ui5 apps and cap service, so is there a way where I can merge my app-router deployment with either ui5 apps or cap service, I have tried all combinations but have not been able to get it working, will surely need your expertise here.
Thanks and Best Regards
Abhishek
Hello Wouter Lemaire Thank you for the detailed example.
Thank for your help.
I think I get it. I was reading this incorrectly. Cross-Mta Configuration is only a discovery service. It only helps pass a "string" that is to be used as an address for the service. I was reading this as similar to a "destination". Sorry for confusion.