Skip to content

RestPack/restpack_serializer

master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
lib
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

restpack_serializer

Build Status Code Climate Dependency Status Gem Version Coverage Status

Model serialization, paging, side-loading and filtering

restpack_serializer allows you to quickly provide a set of RESTful endpoints for your application. It is an implementation of the emerging JSON API standard.

Live Demo of RestPack Serializer


NOTE: This gem needs maintainers: #128


Getting Started

For rails projects:

After adding the gem restpack_serializer to your Gemfile, add this code to config/initializers/restpack_serializer.rb:

Dir[Rails.root.join('app/serializers/**/*.rb')].each do |path|
  require path
end

Serialization

Let's say we have an Album model:

class Album < ActiveRecord::Base
  attr_accessible :title, :year, :artist

  belongs_to :artist
  has_many :songs
end

restpack_serializer allows us to define a corresponding serializer:

class AlbumSerializer
  include RestPack::Serializer
  attributes :id, :title, :year, :artist_id, :href
end

AlbumSerializer.as_json(album) produces:

{
  "id": "1",
  "title": "Kid A",
  "year": 2000,
  "artist_id": 1,
  "href": "/albums/1"
}

as_json accepts an optional context hash parameter which can be used by your Serializers to customize their output:

class AlbumSerializer
  include RestPack::Serializer
  attributes :id, :title, :year, :artist_id, :extras
  optional :score

  can_include :artists, :songs
  can_filter_by :year

  def extras
    if @context[:admin?]
      { markup_percent: 95 }
    end
  end
end
AlbumSerializer.as_json(album, { admin?: true })

All attributes are serialized by default. If you'd like to skip an attribute, you can pass an option in the @context as follows:

AlbumSerializer.as_json(album, { include_title?: false })

You can also define optional attributes which aren't included by default. To include:

AlbumSerializer.as_json(album, { include_score?: true })

Exposing an API

The AlbumSerializer provides page and resource methods which provide paged collection and singular resource GET endpoints.

class AlbumsController < ApplicationController
  def index
    render json: AlbumSerializer.page(params)
  end

  def show
    render json: AlbumSerializer.resource(params)
  end
end

These endpoint will live at URLs such as /albums and /albums/142857:

The AlbumSerializer also provides a single method which will return a serialized resource similar to as_json above.

page, resource and single methods take an optional scope argument allowing us to enforce arbitrary constraints:

AlbumSerializer.page(params, Albums.where("year < 1950"))

In addition to scope, all three methods also accept an optional context hash:

AlbumSerializer.page(params, Albums.where("year < 1950"), { admin?: true })

Other features:

Paging

Collections are paged by default. page and page_size parameters are available:

Paging details are included in a meta attribute:

http://restpack-serializer-sample.herokuapp.com/api/v1/songs.json?page=2&page_size=3 yields:

{
    "songs": [
        {
            "id": "4",
            "title": "How to Dissapear Completely",
            "href": "/songs/4",
            "links": {
                "artist": "1",
                "album": "1"
            }
        },
        {
            "id": "5",
            "title": "Treefingers",
            "href": "/songs/5",
            "links": {
                "artist": "1",
                "album": "1"
            }
        },
        {
            "id": "6",
            "title": "Optimistic",
            "href": "/songs/6",
            "links": {
                "artist": "1",
                "album": "1"
            }
        }
    ],
    "meta": {
        "songs": {
            "page": 2,
            "page_size": 3,
            "count": 42,
            "include": [],
            "page_count": 14,
            "previous_page": 1,
            "next_page": 3,
            "first_href": "/songs?page_size=3",
            "previous_href": "/songs?page_size=3",
            "next_href": "/songs?page=3&page_size=3",
            "last_href": "/songs?page=14&page_size=3"
        }
    },
    "links": {
        "songs.artist": {
            "href": "/artists/{songs.artist}",
            "type": "artists"
        },
        "songs.album": {
            "href": "/albums/{songs.album}",
            "type": "albums"
        }
    }
}

URL Templates to related data are included in the links element. These can be used to construct URLs such as:

  • /artists/1
  • /albums/1

Side-loading

Side-loading allows related resources to be optionally included in a single API response. Valid side-loads can be defined in Serializers by using can_include as follows:

class AlbumSerializer
  include RestPack::Serializer
  attributes :id, :title, :year, :artist_id, :href

  can_include :songs, :artists
end

In this example, we are allowing related songs and artists to be included in API responses. Side-loads can be specifed by using the include parameter:

No side-loads

Side-load related Artists

which yields:

{
    "albums": [
        {
            "id": "1",
            "title": "Kid A",
            "year": 2000,
            "href": "/albums/1",
            "links": {
                "artist": "1"
            }
        },
        {
            "id": "2",
            "title": "Amnesiac",
            "year": 2001,
            "href": "/albums/2",
            "links": {
                "artist": "1"
            }
        },
        {
            "id": "3",
            "title": "Murder Ballads",
            "year": 1996,
            "href": "/albums/3",
            "links": {
                "artist": "2"
            }
        },
        {
            "id": "4",
            "title": "Curtains",
            "year": 2005,
            "href": "/albums/4",
            "links": {
                "artist": "3"
            }
        }
    ],
    "meta": {
        "albums": {
            "page": 1,
            "page_size": 10,
            "count": 4,
            "include": [
                "artists"
            ],
            "page_count": 1,
            "previous_page": null,
            "next_page": null,
            "first_href": '/albums',
            "previous_href": null,
            "next_href": null,
            "last_href": '/albums'
        }
    },
    "links": {
        "albums.songs": {
            "href": "/songs?album_id={albums.id}",
            "type": "songs"
        },
        "albums.artist": {
            "href": "/artists/{albums.artist}",
            "type": "artists"
        },
        "artists.albums": {
            "href": "/albums?artist_id={artists.id}",
            "type": "albums"
        },
        "artists.songs": {
            "href": "/songs?artist_id={artists.id}",
            "type": "songs"
        }
    },
    "linked": {
        "artists": [
            {
                "id": "1",
                "name": "Radiohead",
                "website": "http://radiohead.com/",
                "href": "/artists/1"
            },
            {
                "id": "2",
                "name": "Nick Cave & The Bad Seeds",
                "website": "http://www.nickcave.com/",
                "href": "/artists/2"
            },
            {
                "id": "3",
                "name": "John Frusciante",
                "website": "http://johnfrusciante.com/",
                "href": "/artists/3"
            }
        ]
    }
}

Side-load related Songs

An album :has_many songs, so the side-loaded songs are paged. The meta.songs includes previous_href and next_href which point to the previous and next page of this side-loaded data. These URLs take the form:

Side-load related Artists and Songs

Filtering

Simple filtering based on primary and foreign keys is supported by default:

By primary key:

By foreign key:

Custom filters:

Custom filters can be defined with the can_filter_by option:

class Account
   include RestPack::Serializer
   attributes :id, :application_id, :created_by, :name, :href

   can_filter_by :application_id
end

Side-loading is available when filtering:

Sorting

Sorting attributes can be defined with the can_sort_by option:

class Account
   include RestPack::Serializer
   attributes :id, :application_id, :created_by, :name, :href

   can_sort_by :id, :name
end

Running Tests

bundle rake spec

About

Model serialization, paging, side-loading and filtering

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages