---
title: HATEOAS with Ember Data
teaser: Use links in your JSON to make your Ember app smarter.
tags: web,ember,javascript,rails
author: Simon Taranto
published_on: 2015-03-30
---

Ember Data introduced [strong
conventions](http://emberjs.com/api/data/classes/DS.ActiveModelAdapter.html)
around how to structure API responses. While these conventions allow us to move
quickly, there are additional steps we can take to minimize the coupling between
the front end and back end. Using concepts from
[HATEOAS](https://spring.io/understanding/HATEOAS) (Hypermedia as the Engine of
Application State) we can make our Ember applications more flexible and
resilient to changes on the server.

## Ember Data

Ember Data can take advantage of API responses containing a `links` key pointing
to URLs to associated resources. Ember Data will automatically pick up on those
`links` as the source of the association's data instead of using the default URL
structure. In a use case where we want to asynchronously fetch associated
resources, our API has more flexibility around URL structure.

Let's say we have a `Repo` resource that has many `Commit`s and we want the
`commits` to be loaded asynchronously in Ember. How would we set up our API
endpoints?

## URL structure

By default, Ember Data is going to fetch the commits with a call that looks like
`/commits?ids[]=1&ids[]=4`. For our use case, it makes more sense to have Ember
ask for all of a `repo`'s `commits` without having to know the `commit` id's
ahead of time. We'd like our endpoint to look like `repos/1/commits`. With this
structure the client is able to make requests such as, "Please give me all the
commits for this repo" instead of requests like "Please give me these specific
commits".

## The JSON

Now that we have our URL structure, let's implement the responses themselves.
Using `ActiveModel::Serializer`, our `Repo` serializer looks like this:

```ruby
class Api::V1::RepoSerializer < ActiveModel::Serializer
  attributes(
    :id,
    :links,
    :name,
  )

  def links
    { commits: "/repos/#{object.id}/commits" }
  end
end
```

which produces the following JSON at the `/repos/1` endpoint:

```json
{
  "id": 1,
  "links": {
    "commits": "/repos/1/commits"
  },
  "name": "hound"
}
```

## The front end

We can instruct the `Repo` model to fetch the `commits` asynchronously:

```javascript
import DS from "ember-data";

export default DS.Model.extend({
  name: DS.attr("string"),
  commits: DS.hasMany("commit", { async: true }),
});
```

We're telling Ember Data to lazily fetch the commits from our specified
endpoint. As a result, if we later change our minds that we want the `commits`
resource to be available at a different URL, we can make that change without
touching the front end. The server is able to change its URL structure with no
impact on the front end.

## The HATEOAS Dream

The idea of returning `links` is not a new one.  HATEOAS has been around for some
time and has a specific spec.  It includes a more structured `links` object
including `rel` and `href` keys and a complete URL containing the host name.
Ember Data though asks you to follow the convention of naming the keys in
`links` to match the resource name. A strict HATEOAS implementation of the above
`repo` and `commit`s example would look like:

```json
{
  "id": 1,
  "name": "Hound",
  "links": [ {
    "rel": "commits",
    "href": "http://yourserver.foo/repos/1/commits"
  } ]
}
```

## HATEOAS means flexibility

By combining stronger conventions around our JSON responses with smarter
clients (Ember Data, in this case) we can build more flexible apps with little
to no extra effort.

## What's next

* The [JSON API standard](http://jsonapi.org/)
* [`ActiveModel::Serializer`s](https://github.com/rails-api/active_model_serializers)
