Rethinking Rails API Serialization - Part 3

Posted on 23 Mar 2016 by Eric Oestrich

Part 3 will wrap up this series and show off a full example of how Nagare can be used.

Name fun fact: Nagare (流れ) is Japanese for a stream or flow.

Railtie

The railtie included with Nagare changes the default _render_with_renderer_json method on controllers, similar to ActiveModel::Serializers. You can see a full version of it on github.

A Full Example

Controllers

We start by defining a context that lets the context have a current user. Anything else a serializer might want can be added here.

class ApplicationController < ActionController::Base
  private

  def nagare_context
    @nagare_context ||= Nagare::Context.new({
      current_user: current_user,
    })
  end
end

A regular controller looks like this:

class AdminOrdersController < ApplicationController
  def index
    render({
      json: orders,
      serializers: { collection: AdminOrdersSerializer, item: AdminOrderSerializer },
      context: {
        href: orders_url,
      },
    })
  end

  def show
    render({
      json: order,
      serializers: { item: AdminOrderSerializer },
      context: {
        href: order_url(order),
      },
    })
  end
end

The collection key is required if you have a collection. I found this to be a good pattern when working on Artifact.

Serializers

The serializers are pretty simple. The serializers can customize which attributes will be output. In Artifact I extend these with a custom DSL for [Collection+JSON][cjson] to include links, queries, and templates.

class AdminOrdersSerializer < Nagare::Collection
  # This is the key that will contain all of the serialized items.
  key "orders"

  # You can also have extra attributes on the collection
  attributes :count

  def count
    collection.count
  end
end

Serializers have several ways of obtaining attributes. It can be a method on the serializer itself, the object, or from the context.

class AdminOrderSerializer < Nagare::Item
  # email is a method off of the order
  # item_count is a method we define
  # href comes from the passed in context
  attributes :email, :item_count, :href

  def item_count
    object.items.count
  end
end

attributes defines a method per attribute that will try the object or context for the attribute value. Otherwise you can simply define your own method to use.

Wrapping Up

This brings the Rethinking Rails API Serialization series to a close. I hope you found something useful. Please read over the source for Nagare. I welcome issues or pull requests.

Rethinking Rails API Serializations Series

comments powered by Disqus
Creative Commons License
This site's content is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License unless otherwise specified. Code on this site is licensed under the MIT License unless otherwise specified.