Skip to main content

Making Aurelia/Angular application hosted on PCF (Cloud foundry) 12 factor (#3) complaint.

One of the challenge everyone faces is to make single page applications 12 factor complaint on cloud foundry. This is as of Sep 18, 2017, I didn't knew of any other solutions at the time of writing this blog. This is one of the idea which I thought about that would greatly benefit anyone having this problem. Again, this is just one of the solution to solve the problem and may not suit all your needs.

The problem to solve here is to make single page application factor 3 complaint, where in configuration data should reside in the environment rather than hard code in the app. One of the main variable/constants(s) in question  when it comes to single page application is to make the rest service api-url which servers data to the client reside in environment variable in pcf. One of the approach usually many people recommend is to have different environment related .ts or .js file one for each dev, qa, uat and prod. The problem with this approach is to have different build packages for each running environment and all the constants are hard-coded in the deployment package. This approach also makes it harder to deploy if there are any changes needed to the variables within the app.

As the application is hosted in pcf, the clients should pick up the pcf environment variables on the fly as and when an app is deployed. As such, some piece of code should run on the server, pull the environment variables from cloud foundry and push it to the clients. Single page applications are kinda like thick client application running on User's browser where in the entire application is downloaded at once.

There are 2 approaches to this.

  1. Develop and deploy a Node.js application and listen to the application domain http request where the app is hosted on and modify any java script file on the server and then have this referenced in the index.html. 
  2. Wrap Aurelia in a java web application and let the app modify a .js file when a controller is instantiated and in turn refer this js file from index.html. I followed this approach as java spring is easy to implement.
There are 2 ways in which the handshake could happen. It could be via a java script variable or thru window's sessions storage(key-value). The idea is when the java application is pushed to cloud foundry, the controller is instantiated and a method is executed which pulls the environment variables from cloud foundry and writes to a env.js file. 
for e.g
window.sessionStorage.setItem("restapiurl", "http://blahblah");

Make this env.js accessible from index.html via
<script src="env.js"></script>

So, when any client hits the application, index.html is served from the web server which in-turn pulls the env.js file(with pcf envrionment variables). The single page application could have a base class for all rest-api service typescript files. The baseService.ts could derive the baseurl from this session storage key value.

Our Single page application was developed using Aurelia. As such, the folder structure is in line with java. All one has to do is to add java related folders and have only index.html and env.js(empty) reside in static  and static/js folders respectively as shown below.



The only other thing needed is to make java build tool copy the Aurelia scripts folder onto static java folder before java app is packaged as a war file. This way, the single-page-app is loose coupled and is independent of the deployed environment. If any environment variables is to be changed, all one has to do is to change in pcf and restart the application rather then re-building the app and then redeploying everything all over again. 

The above solution kind of follows BFF (back end for front end) architecture pattern. This approach also does a  ground work for securing the app. The java controller could authenticate the single-page-app as all the calls to the application goes through the controller and this makes it easy to house authentication code which would in turn set some session variables on the client side. This gives more control over the thick client running on user's browser.

Comments