Using EmberJS and Elixir together

Alexandre Pereira
Developers Writing
Published in
5 min readJul 4, 2015

Last year was the year of emberjs for me. I changed my ways from developing ruby on rails apps using server side presentation, to developing a web frontend, SPA, and connecting it to a server api.

While doing this, emberjs and ruby on rails were my preferred platform. I tested and used for a while sailsjs, in nodejs, because I was not happy with ruby concurrency problems ( more concurrency problems then actual speed ).

This year, decidedly will/is the year of elixir. I am currently in love with elixir and phoenix framework, just like I was with ruby on rails in the beginning.

This will be a series of posts, being this the part 1, in how to:

  • create a new phoenix server api
  • using jsonapi package for jsonapi responses
  • add phoenix token auth, to enable authentication
  • creating a user resource
  • add cors
  • access protected users resource

In part 2, I will talk about:

  • create a new emberjs front end with ember-cli
  • add authorization using ember-simple-auth
  • create a login page and protected page

I will not go into how to install and configure elixir or nodejs and ember-cli, since there is already enough tutorials on the web on how to do that. My goal is elixir and emberjs integration.

So, assuming you have a working elixir environment, lets start.

Creating a new phoenix application

mix phoenix.new server_api --no-brunch

This will create a new application, called server_api. The option — no-brunch, is to not add brunch ( nodejs for managing assets ). Mix will ask to fetch and install dependencies, answer Y.

Adding jsonapi and phoenix token auth package to mix.exs dependencies

Add

{:jsonapi, "~> 0.0.2"},
{:plug_cors, "~> 0.7"},
{:phoenix_token_auth, github: "alexjp/phoenix_token_auth"}

to mix.exs. It should look like this:

defp deps do
[{:phoenix, “~> 0.14.0”},
{:phoenix_ecto, “~> 0.4”},
{:postgrex, “>= 0.0.0”},
{:phoenix_html, “~> 1.0”},
{:phoenix_live_reload, “~> 0.4”, only: :dev},
{:cowboy, “~> 1.0”},
{:jsonapi, “~> 0.0.2”},
{:plug_cors, “~> 0.7”},
{:phoenix_token_auth, github: “alexjp/phoenix_token_auth”}]
end

Then just do:

mix deps.get

It should fetch the dependencies.
We will be using a custom phoenix_token_auth from github, because it has some changes to work with ember-simple-auth. This will only be temporary and hopping to soon be able to do a proper pull request to the upstream package. One important change, is that this version uses a single authentication token auth, while upstream uses an array.

Assuming your config/dev.exs is properly configured ( configure database username and password ), we can continue to creating a user resource.

Creating the user resource

mix phoenix.gen.json User users username:string hashed_password:string hashed_confirmation_token:string confirmed_at:datetime hashed_password_reset_token:string unconfirmed_email:string authentication_token:string

This is similar to rails, emberjs, sailsjs generators for resources. Doing phoenix.gen.json, it will generate migration, model, controller, views, changeset and tests.

In the output, it should contain:

Add the resource to your api scope in web/router.ex:

resources "/users", UserController

and then update your repository by running migrations:

mix ecto.migrate

First command will create the users endpoint in the router.
Second command will perform the migration. Before the migration, its best if you do:

mix ecto. create

to create the database.

Editing web/router.ex, you should end up with something like this:

scope "/api", ServerApi do
pipe_through :api
resources "/users", UserController
end

Configuring authentication

In this version of phoenix token auth, the router configuration will be slightly different:

require PhoenixTokenAuth........pipeline :authenticated do
plug PhoenixTokenAuth.Plug
end
scope “/api”, ServerApi do
pipe_through :api
pipe_through :authenticated
resources “/users”, UserController
end
scope “/api” do
pipe_through :api
PhoenixTokenAuth.sessions
PhoenixTokenAuth.register
PhoenixTokenAuth.mount
end

This will allow for a :autenticated pipeline, which all resources in it will need to be authenticated. The session (login/logout) routes, will not be authenticated. But you can change so that register and user management will, simply put them inside :authenticated pipeline.

You can check the routes with:

mix phoenix.routes

Next we will need to configure phoenix token auth. To do this, add in config/config.exs:

config :phoenix_token_auth,
user_model: ServerApi.User,
repo: ServerApi.Repo,
crypto_provider: Comeonin.Bcrypt,
token_validity_in_minutes: 7 * 24 * 60,
user_model_validator: {ServerApi.User, :user_validator}
config :joken,
json_module: PhoenixTokenAuth.PoisonHelper,
algorithm: :HS256,
secret_key: "very secret test key"

This is configuring the model and repo to be used. Also includes support for validations in the model.
We also setup the joken configuration, the secret_key should be in dev/prod/test environments, I will keep it together for simplicity reasons.

In web/models/user.ex, add:

def user_validator(changeset = %{params: %{"password" => password}}) when password != nil and password != "" do
if String.length(password) < 6 do
changeset = Ecto.Changeset.add_error(changeset, :password, :too_short)
end
changeset
end
def user_validator(changeset), do: changeset

as the :user_validator configured above in config/config.exs

Configuring jsonapi

The controllers and views are configured to normal json responses. To enable jsonapi responses, we will have to change the user controller and view.

In the controller, the changes are simple:
Where there is this:

render(conn, "index.json", users: users)

change to

render conn, "index.json", %{data: users, params: _params}

and

render(conn, "show.json", user: user) 
or
render conn, "show.json", user: user

change to

render conn, "show.json", %{data: user}

In the view,

def render("index.json", %{users: users}) do
%{data: render_many(users, "user.json")}
end
def render("show.json", %{user: user}) do
%{data: render_one(user, "user.json")}
end
def render("user.json", %{user: user}) do
%{id: user.id}
end

change to

use JSONAPI.PhoenixViewdef type, do: "user"def attributes(model) do
Map.take(model, [:name,
:username,
:email])
end
def relationships() do
%{
}
end
def url_func() do
&user_url/3
end

Adding cors

Plugcors will enable managing cors, needed later for emberjs.
To enable cors, its necessary to add:

plug PlugCors

to the lib/server_api/endpoint.ex, before plug :router. It should look like this:

......
plug PlugCors
plug :router, ServerApi.Router

In web/router.ex, replace:

pipeline :api do
plug :accepts, ["json"]
end

with

pipeline :api do
plug :accepts, ["json"]
plug PlugCors, [origins: ["*"]]
end

This will enable cors for all origins. Later, we should specify the server where emberjs is.

Taking it for a test drive

Bringing the server online with mix phoenix.server and using an app like chromium postman, you can test the url :

localhost:4000/api/users

. You should receive a :

{"error":"Not authorized"}

Sending:

{"user": {"username": "userexample", "email": "user@example.com", "password": "secret"}}

to the route:

localhost:4000/api/auth/users

should yield a response of:

{"status":"ok","confirmation_token": "BZ7FZf0MqZ4enqi0XMsUyp9NHaxYzzLdLJcyeaOTEzIJtYhFjgIb5zFDWSnZ8FsOqLmMshH0Dw1u1WUj5hYHzQ"}

Confirming the user, sending:

{"confirmation_token":"BZ7FZf0MqZ4enqi0XMsUyp9NHaxYzzLdLJcyeaOTEzIJtYhFjgIb5zFDWSnZ8FsOqLmMshH0Dw1u1WUj5hYHzQ"}

to the route:
localhost:4000/api/auth/users/1/confirm

should yield a response of:

{"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl9pZCI6IkZpbjUrMU85SncyV3hGV3pmYjB5UFZPZ3pySU5UclJpIiwiaWQiOjQsImV4cCI6MTQzNjYyMTU2NX0.gQsCpAT8PJNWPbE0HCJPzjStVP-AJCpTSAvspig4PpY"
}

Sending to route:

localhost:4000/api/auth/sessions
json:
{"username": "userexample", "password": "secret", "grant_type": "password"}

should yield:

{"user_id":1,"token_type":"bearer","access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl9pZCI6IkZpbjUrMU85SncyV3hGV3pmYjB5UFZPZ3pySU5UclJpIiwiaWQiOjQsImV4cCI6MTQzNjYyMTU2NX0.gQsCpAT8PJNWPbE0HCJPzjStVP-AJCpTSAvspig4PpY"}

Finally, testing it by querying users, authenticated:

Add this to the headers in postman:

Authorization: Bearer
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl9pZCI6IkZpbjUrMU85SncyV3hGV3pmYjB5UFZPZ3pySU5UclJpIiwiaWQiOjQsImV4cCI6MTQzNjYyMTU2NX0.gQsCpAT8PJNWPbE0HCJPzjStVP-AJCpTSAvspig4PpY

You should be able to see the list of users ( as without it, you should receive a not authenticated response ).

Wrapping up

With this base you should be able to use elixir as a server api with authorization for emberjs.

Ember-simple-auth, will send the login json like in the above example and it should work out of the box with ember data.

Next up, creating the emberjs app and connecting it to elixir server api.

--

--