---
title: 'Backbone.js, JSON API, and Relational Data: A Primer'
teaser:
tags: web,rails,javascript
author: Josh Clayton
published_on: 2013-10-02
---

While following patterns suggested by [JSON API][json-api] with
[Ember][ember-js] may be straightforward, little documentation exists for its
usage within [Backbone.js][backbone-js]. With feed-readers popular in the past
few months, I've decided to demonstrate how to follow the specification
defined by [JSON API][json-api] to provide data to a Backbone application;
namely, how to populate collections and models with associated data.

## The Application API

Let's start with the Rails application's <abbr title="Application Programming Interface">API</abbr> implementation, which is fairly straightforward:

    # app/controllers/api/feeds_controller.rb
    class Api::FeedsController < ApplicationController
      respond_to :json

      def index
        feeds = Feed.rss
        respond_with feeds, each_serializer: FeedSerializer
      end

      def show
        feeds = Feed.where(id: params[:id]).rss
        respond_with feeds, each_serializer: FeedSerializer
      end
    end

The controller is using [ActiveModel::Serializers][active-model-serializers]
to generate <abbr title="JavaScript Object Notation">JSON</abbr> responses for both `Feed` and `Entry` objects.

    # app/serializers/feed_serializer.rb
    class FeedSerializer < ActiveModel::Serializer
      attributes :id, :title, :url, :feed_url, :etag, :description

      has_many :entries, serializer: EntrySerializer,
        embed: :ids, include: true, key: :entries
    end

    # app/serializers/entry_serializer.rb
    class EntrySerializer < ActiveModel::Serializer
      attributes :id, :url, :title, :published, :author, :content

      def content
        object.content || object.summary
      end
    end

These classes result in a <abbr title="JavaScript Object Notation">JSON</abbr> structure like this when retrieving `api/feeds.json`:

    {
      "entries"=> [
        {"id"=>"a9f9283c34af5c6f7ab6fc461e5ba8ee",
          "url"=> "",
          "title"=> "",
          "published"=>"2013-09-22T18:25:02Z",
          "author"=>"",
          "content"=>""},
        {"id"=>"e805ed779257cd0d1f69b747fb01b591",
          "url"=> "",
          "title"=>"",
          "published"=>"2013-09-22T18:16:06Z",
          "author"=>"",
          "content"=> ""},
        {"id"=>"6601a53c98e690a46b8bbeca46a6904a",
          "url"=>"",
          "title"=>"",
          "published"=>"2013-08-30T15:16:03Z",
          "author"=>"",
          "content"=> ""}
      ],
      "feeds"=> [
        {"id"=>"e74786582200ea744c0d0a72fc616199",
          "title"=>"",
          "url"=>"",
          "feed_url"=>"",
          "etag"=>"\"4762e3773a5404de50dcfaef49697460\"",
          "description"=>"",
          "entries"=> ["a9f9283c34af5c6f7ab6fc461e5ba8ee", "e805ed779257cd0d1f69b747fb01b591"]},
        {"id"=>"1a33061dccfdc80aff5ce04df9591f6e",
          "title"=>"",
          "url"=>"",
          "feed_url"=>"",
          "etag"=>"\"7896d-eaef-4e6c07d3b7300\"",
          "description"=> "",
          "entries" => ["6601a53c98e690a46b8bbeca46a6904a"]}
      ]
    }

There are two keys, `feeds` and `entries`, returned. Each item within `feeds`
maintains a reference to its list of entry IDs, which will need to be
associated when building up the structure within the Backbone collection.

## The Backbone Application

Let's look at the Backbone collection:

    # app/assets/javascripts/collections/feeds.coffee
    class @App.Collections.Feeds extends Backbone.Collection
      model: App.Models.Feed
      url: '/api/feeds'
      parse: (response) =>
        @entries = response.entries
        response.feeds

`parse` is doing most of the heavy lifting here, assigning a property
`entries` to the collection (to be used later) and returning `response.feeds`,
which gets assigned internally to `models()`.

With the collection of feeds knowing about `entries`, it becomes the
responsibility of each `App.Models.Feed` to correctly reference each
`App.Models.Entry`:

    # app/assets/javascripts/models/feed.coffee
    class @App.Models.Feed extends Backbone.RelationalModel
      relations: [
        {
          type: Backbone.HasMany
          relatedModel: 'App.Models.Entry'
          collectionType: 'App.Collections.Entries'
          key: 'entries'
        }
      ]

      initialize: ->
        @set 'entries', _.filter @collection.entries, (entry) =>
          _.indexOf(@get('entries'), entry.id) >= 0

      title: ->
        @get 'title'

      description: ->
        @get 'description'

      entries: ->
        @get 'entries'

Within `App.Models.Feed`'s `initialize`, we bootstrap the <abbr title="JavaScript Object Notation">JSON</abbr> data from the collection's `entries` into the `entries` attribute on the `App.Models.Feed` model. Because the `entries` array may contain IDs of entries for other feeds, however, we filter out everything that doesn't belong. Once the records have been filtered correctly, [Backbone-relational.js][backbone-relational] handles the rest.

For reference, here are `App.Models.Entry` and `App.Collections.Entries`:

    # app/assets/javascripts/models/entry.coffee
    class @FeedMe.Models.Entry extends Backbone.RelationalModel
      title: ->
        @get 'title'

      url: ->
        @get 'url'

      published: ->
        @get 'published'

      content: ->
        @get 'content'

      author: ->
        @get 'author'

    # app/assets/javascripts/collections/entries.coffee
    class @FeedMe.Collections.Entries extends Backbone.Collection
      model: FeedMe.Models.Entry

## Results

While there is a bit of wiring involved, it's fairly easy to set up a Backbone app to interact with associated data provided by an <abbr title="Application Programming Interface">API</abbr> following the patterns of [JSON API][json-api]. If you're using [Marionette.js][marionette-js] to handle associated data and have examples to share, tweet [@thoughtbot][thoughtbot-twitter] to let us know!

## Learn More About Backbone.js

If you're interested in learning how to build Backbone apps, I recommend you check out thoughtbot's book [Backbone.js on Rails][backbone-js-on-rails], which includes an example app in addition to the book itself.

[json-api]: http://jsonapi.org
[ember-js]: http://emberjs.com
[backbone-js]: http://backbonejs.org
[backbone-relational]: http://backbonerelational.org
[active-model-serializers]: https://github.com/rails-api/active_model_serializers
[marionette-js]: http://marionettejs.com
[thoughtbot-twitter]: https://twitter.com/thoughtbot

[backbone-js-on-rails]: https://backbonejsonrails.com?utm_source=giantrobots&utm_medium=blog&utm_campaign=jsonapibackbonerelational
