Hosting an EmberJS app with a backend API

In the mu.semte.ch framework we use EmberJS in the frontend. The data is retrieved through Ember Data or AJAX requests, via the identifier and dispatcher, from the microservices in the backend. Aad Versteden has already explained in a previous blog post how to use  an Ember docker to facilitate the development with ember-cli and connect to the backend microservices through a proxy. In this article we will focus on the hosting of an Ember application in a production environment using the Ember proxy service docker image.

Hosting the app on an HTTP server

The frontend application is basically a collection of static javascript, HTML, CSS, … files that need to be hosted on an HTTP server like Nginx or Apache. Besides just hosting the static files, the HTTP server also needs to proxy specific requests to the backend API. How does the HTTP server know which requests should be served by the Ember app and which requests should be proxied to the backend?

What’s typically done, is hosting the backend API on the /api path. As a result the HTTP server can decide with a simple regex on the request URL whether the request must be served by the Ember app or by the backend API. This approach however puts a limit on your backend API since all the API paths must start with /api.

To circumvent this limitation on the backend we’ve created a Nginx proxy service that just does what you need. Just add your frontend app and it will automatically make the Ember app serve all HTML requests and requests to a path matching the regex ^/(assets|font)/. All remaining requests will be proxied to the backend. Have a look at the Nginx configuration in the container if you want to know how this works in depth (it makes use of the 418 I’m a teapot HTTP status code 🙂 ).

How to use the Nginx proxy service

Before we can create our proxy service, we first need to build the Ember application. Using edi you can do this with the following command:

edi ember build -prod

The built application will by default be available in the dist/ folder of your frontend application.

We now need the files in the dist/ folder to be hosted by the proxy service. Therefore, we will extend the Nginx proxy service image with our built application. Just create a Dockerfile in your frontend application’s folder with the following contents:

FROM semtech/mu-nginx-spa-proxy:1.1.0
COPY dist/ app/

Next, assuming dist/ contains the latest production build of your application, build the Docker image (or configure an automated build on Docker Hub):

docker build -t my-ember-app .

Finally, add the resulting image to your mu.semte.ch docker-compose.yml and link the identifier microservice as backend to the proxy service:

version: '2'
services:
  ...
  frontend:
    image: my-ember-app
    links:
      - identifier:backend

Custom configuration

The Nginx proxy service has a couple of configuration options. The regex of requests paths that must be served by the Ember app is set to ^/(assets|font)/ by default, but can be configured through the STATIC_FOLDERS_REGEX environment variable.

For example, with the following configuration the Ember app will also serve paths starting with /images .

FROM semtech/mu-nginx-spa-proxy:1.1.0
COPY dist/ app/
ENV STATIC_FOLDERS_REGEX "^/(assets|font|images)/"

You can also add some custom Nginx configuration by adding one or more *.conf files in the /config folder. They will be automatically picked up by Nginx.

For example, if you want to increase the client_max_body_size, create a file_upload.conf file with the following contents:

client_max_body_size 50M;

Add the file_upload.conf file to the /config in your Docker image:

FROM semtech/mu-nginx-spa-proxy:1.1.0
COPY dist/ app/
COPY file_upload.conf /config

Conclusion

The Nginx proxy service offers a simple and configurable solution to host an EmberJS application on an HTTP service with a proxy to the backend API without putting limitations on the backend request paths. In fact, the proxy service can also be used with other single page app technologies than EmberJS like for example Angular or React.