Building a performant real-time web app with Ember Fastboot and Phoenix (Part 1)
This article is part 1 in a series
Part 1: The meeting of two well-aligned, opinionated frameworks
Part 2: Users and Authentication (API)
Part 2.1: Some small adjustments to your API
Part 3: Users and Authentication (UI)
Part 4: Logging in to our API & ember-simple-auth
Part 5: Building a CRUD resource
Part 6: Animating your UI with liquid-fire
Part 7: Room UI & Messages
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 (╯°□°）╯︵ ┻━┻).
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.
- 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
- 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.
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
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)
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.
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”
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
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 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
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
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>
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"
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
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
mix phoenix.new peepchat --no-html --no-brunch
mv peepchat api
And start your new API up
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.
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.
mix deps.compile plug
MIX_ENV=test mix deps.compile plug
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
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:
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.
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
should be handled by the following controller and action
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
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
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
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
and see that your API works by going to /api/session and seeing the expected API response.
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.
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…