Rethinking Rails API Serialization - Part 2

Posted on 22 Mar 2016 by Eric Oestrich

Part 2 of this series will show off snippets of a new gem I created, Nagare. The gem is pretty small so give it a read through. Part 3 will show off more of the gem, this post will concentrate on the specific issues I had in the first post.

General Context

The first thing I wanted to tackle is injecting context to the serializer. I do this by making you specify everything you want the serializer to know about. The default context has nothing.

class ApplicationController < ActionController::Base
  def nagare_context
    @nagare_context ||= Nagare::Context.new({
      current_user: current_user,
    })
  end
end

It's simple to create a new context and you can even override it in specific controllers because it's just a method. I tend to use my letter gem here to handle memoization for me.

Resource Context

Next up is context on the resource level. This is similar to how I injected context by ActiveModel::Serializers, the biggest difference is the key change.

def index
  render({
    context: {
      href: books_url,
    },
  })
end

This hash extends the general context so you can easily override specific keys if necessary.

Collection Serializers

Collection serializers are a subclass of an item serializer in Nagare. This gives them the full capability of attribute and the context.

class BooksSerializer < Nagare::Collection
  attribute :count, :href

  def count
    collection.count
  end
end

href is coming from the context, if we think of this rendering in the index method shown above.

Explicit Resources

Nagare requires you to explicitly set the serializer for it to do anything. This is how I prefer it because I almost never tended to use the automatic serializer choice.

def index
  render({
    serializers: { collection: BooksSerializer, item: BookSerializer },
  })
end

Adapters

This was one thing I really liked from ActiveModel::Serializers and copied for Nagare. ActiveModel::Serializers lets you define an adapter that can completely reshape the JSON before it leaves your app. I used this for Collection+JSON with ActiveModel::Serializers.

Nagare's version of adapters is pretty simple to start. The only interface is #as_json. Here is the full default adapter:

class Adapter
  def initialize(serializer, collection: false)
    @serializer = serializer
    @collection = collection
  end

  def as_json(options = nil)
    serializer.as_json(options)
  end

  private

  attr_reader :serializer, :collection
end

This is pretty simple, but you have a hook into doing more complicated things like Collection+JSON or JSON API.

Part 3

Next post I'll show off how to use Nagare further.

Rethinking Rails API Serializations Series

comments powered by Disqus
Eric Oestrich
I am:
All posts
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.