Building a performant real-time web app with Ember Fastboot and Phoenix (Part 1)

The meeting of two well-aligned, opinionated frameworks

Ember.js and Phoenix are both opinionated web app frameworks, which aim to reduce the number of trivial decisions that developers typically must make every day. In doing so, these frameworks aim to empower users by boosting their productivity, allowing them to focus on what makes their app unique and special. Sharing a set of opinions across a large community presents numerous benefits, including a high degree of interoperability, a singular clear set of libraries and tools that all efforts can be focused on, the ability to hire someone who will hit the ground running and start shipping code within their first day at the office, and more!

If you believe that your time better is spent figuring out an entirely new way of syncing up data with DOM, or that your users will celebrate the time spent building a brand new UI router that does largely the same thing as dozens of other readily-available open source projects, this article is probably going to make you want to (╯°□°）╯︵ ┻━┻).

Project Structure

We’re going to aim to have two completely separate projects for this exercise. The aim is to be able to deploy our API and UI separately, while taking advantage of best-in-class build tools for each. There are additional considerations that one must take into account when building a system in this way, but that’s beyond the scope of this article.

Where we’re going

We’re going to build a single-page app with Ember.js and a RESTful API using Phoenix. This will include…

Using JSON-API as a standard for JSON contracts

Using ember-cli-fastboot for lightning-fast server-side rendering of our UI

Harnessing the power of Phoenix channels and websockets to build a scalable, real-time connection from this API to each browser

Using ember-simple-auth and guardian, to roll our own OAuth2 authentication, build around the JWT standard.

Deploying both your UI and API to Heroku, using SSL encryption for data in transport, over both HTTP and websockets

We’ll be working with essentially two different tech stacks here, so we’ll have to set a few things up… I’m using OS X, so windows users may have to do things a little differently.

The Front

Get the latest version of node.js. Many older versions will work and are fine, but are marginally less awesome. The cool kids are using the latest stuff, you should too.

Install the latest version of ember-cli (2.4.3 at this time) by running

npm install -g ember-cli

The Back

Make sure you have a recent version of Postgres installed, and that your local user has the ability to create new databases. I recommend installing it with homebrew. Instructions for this (and other installation options) are here.

You’ll want to get set up with Elixir, Mix and Phoenix. Detailed instructions are here

The Other Stuff

Eventually, we’re going to deploy everything to Heroku, so you’ll need to get set up there. They have an awesome CLI tool that you should definitely download and start using.

We’ll use GitHub for source control management. Make sure you sign up, and set up your SSH keys.

We’ll use Travis-CI for our testing and continuous deploy pipeline, so make sure you’ve signed up there.

First pass at the UI

I’m going to begin by creating a folder to hold both the UI and API, just to stay organized.

cd ~

mkdir peepchat

I’ll then create the UI, using ember-cli’s application blueprint (essentially a dynamic template for a new application). We’ll also name the folder that ember-cli puts this project in, using the -dir argument

cd peepchat

ember new peepchat -dir ui

Ember-cli will create the files for your initial starting point, and begin installing dependencies; this may take a few moments.

Once this process completes, you’ll still be in your peepchat folder, enter the project, and start up the ember-cli development web server using the ember serve command (you could also use ember s, which does the same thing)

cd ui

ember serve

You should see an indication that the app has started up, and is available on http://localhost:4200/. Try going to that URL in your browser. You should see the following on your screen.

Your Ember.js UI is up and running after only one command in your terminal!

Server-side rendering with Ember Fastboot

Congratulations, you now have a working ember.js app! While we’re here, let’s take a look at the HTML that ember-cli is emitting, by right-clicking on the webpage and clicking “view source”

The usual Ember.js client-side rendering

You’ll see that the html <body> just contains some script tags, with no visible content (this is expected). Ember adds the visible content on the screen after the app loads — this is known as client-side rendering. Let’s add ember’s server-side rendering technology right now, so it’s in place as we move forward. To do this, go back to your terminal, hit Ctrl+C to kill the running ember-cli development server, and run

ember install ember-cli-fastboot

Once this completes, you should be able to run

ember fastboot --serve-assets

and your app will start on http://localhost:3000. Do the view source thing again, and you’ll see that the HTTP response that hits the browser now contains the rendered HTML

Ember Fastboot server-side rendering in action!

The first UI deploy

Now let’s get our UI deployed. You’ll want to create a new app using the officially supported heroku ember.js buildpack. The buildpack tells Heroku how to build your app from the source code, and how to start it up in production.



heroku buildpacks:set heroku createheroku buildpacks:set https://codon-buildpacks.s3.amazonaws.com/buildpacks/heroku/emberjs.tgz

You can then deploy your app by pushing to the new git remote that heroku has set up for you, and open it in your default browser

git push heroku master

heroku open

While you’re at it, create a new repository for your UI on github, and push it up there as well using

git push -u origin master

The “-u” argument will ensure that subsequent pushes go to GitHub.

Setting up continuous deploy

Head on over to Travis-CI.org and login. Go to your profile press the Sync Account button, and turn on the switch next to the GitHub repository you just created.

You may need to sync travis-ci with Github

We can now install the Travis-ci command line client

gem install travis

and set Travis CI up to deploy to Heroku automatically for passing builds, by running this in your console

travis setup heroku

NOTE: It’s definitely a good idea to allow Travis to encrypt your deploy keys, when it asks.

If you look at your .travis.yml file, you’ll see some encrypted content has been added. Let’s make one last change to see if the automatic deployment works, by updating app/templates/application.hbs

<h2 id=”title”>Welcome to Ember</h2>

<h4>(with fastboot, on heroku!)</h4>

{{outlet}}

You may also need to make some additional changes to your .travis.yml, because Travis CI’s default C++ compiler doesn’t always work with newer versions of node.js. Commit this change, in addition to the .travis.yml changes, and push it all up to GitHub.

git add -A .

git commit -m "Continuous deploy with Heroku"

git push

If you look at Travis CI, you will soon see a build starting. When this is finish, check your Heroku app to see if your change has been deployed for you

heroku open

Our first continuously-deployed UI change!

Congrats, you now have a CI/CD pipeline, which auto-deploys successful builds from master! Next, we’ll set something similar up for your back end.

First Pass at the API

First, let’s go back to our peepchat directory, and create a new phoenix app

cd ~/peepchat

mix phoenix.new peepchat --no-html --no-brunch

mv peepchat api

cd api

And start your new API up

mix phoenix.server

You’ll see an indication in the console that your API has started on http://localhost:4000.

Attempting to visit this URL in your browser will show an error message, because you haven’t set up any routes.

Our first peek at Phoenix

A new mime type

The JSON-API standard requires that we handle the mime type application/vnd.api+json. To set this up, open ./config/config.exs and add the following code before the import_config line

Finally, to complete the addition of our new JSON-API mime type, we must touch a file and recompile plug so that this new configuration is taken into account in our app.

touch deps/plug/mix.exs

mix deps.compile plug

MIX_ENV=test mix deps.compile plug

CORS

Because our API will be set up on a different hostname than our UI, we’ll need to set up CORS to allow the browser to make requests across origins. This can be done easily via cors_plug.

First, go to your mixfile (./mix.exs) and add cors_plug to your dependencies

go to your console and type

mix deps.get

to install this new dependency. Finally go to your endpoint (./lib/peepchat/endpoint.ex) and add the plug immediately above your router

Adding your first API endpoint

Let’s add an endpoint that returns something static, just to get started. Create a file web/controllers/session_controller.ex with the following contents:

A controller that doesn’t do much

Now that we have a controller, we need to start routing traffic to it. This is done through the Phoenix router. Open web/router.ex and add your SessionController to it as shown below. Also, while you’re here, set the :api pipeline up so that it accepts the json-api mime type we configured earlier.

Adding our session controller to the Phoenix router

While we’re here, let’s talk about the concept of a resource. It’s basically a way of setting up multiple routes, according to Phoenix conventions (aligned with Rails router conventions). You can read more about it here, but in this case, we’re basically saying that URLs matching the following

/api/session

should be handled by the following controller and action

SessionController#index

If you look at the SessionController we just created, there’s an index method, which returns a static piece of JSON. Check that all of this wonderful stuff connects the way we intended, by visiting the URL http://localhost:4000/api/session in your favorite browser. You should see something like this

If you use Chrome, and want your JSON to look pretty like mine, download and install the JSONView Chrome extension.

Now, let’s set up Heroku for our new API project. First, because Phoenix doesn’t set up Git for us, you’ll want to create a new repository

git init

Now we’ll have to do a few things to get our project ready for production. First, we don’t want to check a production secret_key into GitHub. Open your config/prod.exs and update it to look like this:

Here’s what we’ve done:

read our secret_key from an environment variable

read our DB connection URL from an environment variable too

Then, make the initial git commit for your project

git add -A .

git commit -m "My first Phoenix API"

The next step is creating a new Heroku app, and pushing our project up to it. This will feel very similar to what we did for the UI — just with a different buildpack.

heroku create --buildpack "https://github.com/HashNuke/heroku-buildpack-elixir.git"

Take note of the app name. We’re going to make another change to config/prod.exs, so that it only responds to HTTPS, and only on the domain setup by Heroku.

Finally, let’s make sure our environment variables are setup the way we want. Start by telling mix to create a new secret for you, and setting it as an env variable on your Heroku app

mix phoenix.gen.secret

> IpntQSPL........2bhRu0bS3u/G

heroku config:set SECRET_KEY_BASE=IpntQSPL........2bhRu0bS3u/G

And let’s have Heroku create a little (free) Postgres database for us

heroku addons:create heroku-postgresql:hobby-dev

you should now be able to run

heroku config

and see reasonable values for both the DATABASE_URL and SECRET_KEY_BASE environment variables.

Two last things we’ll want to do. The first is to bind our API to the hostname that Heroku picked for our app, and force all traffic to come over HTTPS

And also we need to tell Heroku how to start our app up. To do this, we’ll create a really simple Procfile in the root of our project, by running the following command in the terminal:

echo "web: elixir -S mix phoenix.server" > Procfile

Stage everything, make a git commit, push to Heroku

git add -A .

git commit -m "Ready for Heroku"

git push heroku master

After Heroku has done its thing, you should be able to run

heroku open

and see that your API works by going to /api/session and seeing the expected API response.

Continuous Integration

Create a file called .travis.yml in the root of your project

Create a new repository for your API on GitHub, and push your code up there. Go to Travis CI and turn on continuous integration for this new repository, just like we did for the UI. Now you can use the Heroku and Travis command line tools together again, to securely set up automatic deployment.

travis setup heroku

you should see that a change has been made to your .travis.yml as a result of running this command. Commit the change, and push it up to GitHub. After travis does its thing, it should automatically deploy to Heroku now.

Congratulations!

You now have CI/CD set up for both your UI and API. You can go ahead and remove the Heroku git remote from both your UI and API projects, since you’ll be relying on Travis to do your deployment from now on (and only when tests pass!).

git remote rm heroku

In Part 2, we’ll set create the concept of a “User” in our system, and set up secure authentication using ember-simple-auth and guardian…