Fast::Json::Serializer

This gem generates the JSON bypassing ActiveRecord object creation, which make JSON generation blazing fast! It uses ActiveRecord::Base.connection.execute method which returns PG::Result. JSON is generated by iterating over the collection.

Installation

Add this line to your application's Gemfile:

gem 'fast-json-serializer'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install fast-json-serializer

Usage

Create a app/serializers/application_serializer.rb with the following code:

# app/serializers/application_serializer.rb

require 'fast/json/serializer/base'

class ApplicationSerializer < Fast::Json::Serializer::Base
end

Make the other serializers a subclass of the ApplicationSerializer class

# app/serializers/post_serializer.rb

class PostSerializer < ApplicationSerializer
  # enable FastJsonapi format by uncommenting this line
  # set_type :post

  attributes :id, :title, :creator_name, :creator_email

  # use a ruby/rails formatter
  attribute :created_at, format: :to_s
  attribute :updated_at, format: :to_s

  # rename the json key name
  attribute :created_at_epoch, column_name: :created_at, format: :to_i
  attribute :updated_at_epoch, column_name: :updated_at, format: :to_i

  # use custom method
  attribute :created_at_ist do |serializer, hash|
    serializer.ist_time(hash['created_at'])
  end

  attribute :updated_at_ist do |serializer, hash|
    serializer.ist_time(hash['updated_at'])
  end

  # a class method can be used as well 
  def ist_time(timestamp)
    return unless timestamp

    timestamp.in_time_zone("Kolkata").strftime('%A - %b %d, %Y')
  end
end

Formatting of the JSON

Currently, it supports two formats, key-value, and FastJsonapi format

PostSerializer.new(Post.limit(10)).serialized_json

produces, with set_type :post enabled:

{
  "data": [
    {
      "id": 1,
      "type": "post",
      "attributes": {
        "id": 1,
        "title": "Tacos",
        "creator_name": "Ella Erdman",
        "creator_email": "[email protected]",
        "created_at": "2022-10-13 05:51:08 UTC",
        "updated_at": "2022-10-13 05:51:08 UTC",
        "created_at_epoch": 1665640268,
        "updated_at_epoch": 1665640268,
        "created_at_ist": "Thursday - Oct 13, 2022",
        "updated_at_ist": "Thursday - Oct 13, 2022"
      }
    },
    {
      "id": 2,
      "type": "post",
      "attributes": {
        "id": 2,
        "title": "Barbecue Ribs",
        "creator_name": "Mrs. Fern Yundt",
        "creator_email": "[email protected]",
        "created_at": "2022-10-13 05:51:08 UTC",
        "updated_at": "2022-10-13 05:51:08 UTC",
        "created_at_epoch": 1665640268,
        "updated_at_epoch": 1665640268,
        "created_at_ist": "Thursday - Oct 13, 2022",
        "updated_at_ist": "Thursday - Oct 13, 2022"
      }
    },
    {
      "id": 69,
      "type": "post",
      "attributes": {
        "id": 69,
        "title": "French Fries with Sausages",
        "creator_name": "Vance Connelly",
        "creator_email": "[email protected]",
        "created_at": "2022-10-13 05:51:08 UTC",
        "updated_at": "2022-10-13 05:51:08 UTC",
        "created_at_epoch": 1665640268,
        "updated_at_epoch": 1665640268,
        "created_at_ist": "Thursday - Oct 13, 2022",
        "updated_at_ist": "Thursday - Oct 13, 2022"
      }
    },
    {
      "id": 3,
      "type": "post",
      "attributes": {
        "id": 3,
        "title": "Pork Belly Buns",
        "creator_name": "Mrs. Willie Green",
        "creator_email": "[email protected]",
        "created_at": "2022-10-13 05:51:08 UTC",
        "updated_at": "2022-10-13 05:51:08 UTC",
        "created_at_epoch": 1665640268,
        "updated_at_epoch": 1665640268,
        "created_at_ist": "Thursday - Oct 13, 2022",
        "updated_at_ist": "Thursday - Oct 13, 2022"
      }
    },
    {
      "id": 4,
      "type": "post",
      "attributes": {
        "id": 4,
        "title": "Peking Duck",
        "creator_name": "Joselyn VonRueden",
        "creator_email": "[email protected]",
        "created_at": "2022-10-13 05:51:08 UTC",
        "updated_at": "2022-10-13 05:51:08 UTC",
        "created_at_epoch": 1665640268,
        "updated_at_epoch": 1665640268,
        "created_at_ist": "Thursday - Oct 13, 2022",
        "updated_at_ist": "Thursday - Oct 13, 2022"
      }
    },
    {
      "id": 5,
      "type": "post",
      "attributes": {
        "id": 5,
        "title": "Hummus",
        "creator_name": "Stacee Pfannerstill",
        "creator_email": "[email protected]",
        "created_at": "2022-10-13 05:51:08 UTC",
        "updated_at": "2022-10-13 05:51:08 UTC",
        "created_at_epoch": 1665640268,
        "updated_at_epoch": 1665640268,
        "created_at_ist": "Thursday - Oct 13, 2022",
        "updated_at_ist": "Thursday - Oct 13, 2022"
      }
    },
    {
      "id": 6,
      "type": "post",
      "attributes": {
        "id": 6,
        "title": "California Maki",
        "creator_name": "Fidel Schroeder",
        "creator_email": "[email protected]",
        "created_at": "2022-10-13 05:51:08 UTC",
        "updated_at": "2022-10-13 05:51:08 UTC",
        "created_at_epoch": 1665640268,
        "updated_at_epoch": 1665640268,
        "created_at_ist": "Thursday - Oct 13, 2022",
        "updated_at_ist": "Thursday - Oct 13, 2022"
      }
    },
    {
      "id": 7,
      "type": "post",
      "attributes": {
        "id": 7,
        "title": "French Toast",
        "creator_name": "Alvaro Berge",
        "creator_email": "[email protected]",
        "created_at": "2022-10-13 05:51:08 UTC",
        "updated_at": "2022-10-13 05:51:08 UTC",
        "created_at_epoch": 1665640268,
        "updated_at_epoch": 1665640268,
        "created_at_ist": "Thursday - Oct 13, 2022",
        "updated_at_ist": "Thursday - Oct 13, 2022"
      }
    },
    {
      "id": 8,
      "type": "post",
      "attributes": {
        "id": 8,
        "title": "Arepas",
        "creator_name": "Alva Kris DO",
        "creator_email": "[email protected]",
        "created_at": "2022-10-13 05:51:08 UTC",
        "updated_at": "2022-10-13 05:51:08 UTC",
        "created_at_epoch": 1665640268,
        "updated_at_epoch": 1665640268,
        "created_at_ist": "Thursday - Oct 13, 2022",
        "updated_at_ist": "Thursday - Oct 13, 2022"
      }
    },
    {
      "id": 9,
      "type": "post",
      "attributes": {
        "id": 9,
        "title": "Meatballs with Sauce",
        "creator_name": "Willie Kuhic",
        "creator_email": "[email protected]",
        "created_at": "2022-10-13 05:51:08 UTC",
        "updated_at": "2022-10-13 05:51:08 UTC",
        "created_at_epoch": 1665640268,
        "updated_at_epoch": 1665640268,
        "created_at_ist": "Thursday - Oct 13, 2022",
        "updated_at_ist": "Thursday - Oct 13, 2022"
      }
    }
  ]
}

and with set_type :post disabled

[
  {
    "id": 1,
    "title": "Tacos",
    "creator_name": "Ella Erdman",
    "creator_email": "[email protected]",
    "created_at": "2022-10-13 05:51:08 UTC",
    "updated_at": "2022-10-13 05:51:08 UTC",
    "created_at_epoch": 1665640268,
    "updated_at_epoch": 1665640268,
    "created_at_ist": "Thursday - Oct 13, 2022",
    "updated_at_ist": "Thursday - Oct 13, 2022"
  },
  {
    "id": 2,
    "title": "Barbecue Ribs",
    "creator_name": "Mrs. Fern Yundt",
    "creator_email": "[email protected]",
    "created_at": "2022-10-13 05:51:08 UTC",
    "updated_at": "2022-10-13 05:51:08 UTC",
    "created_at_epoch": 1665640268,
    "updated_at_epoch": 1665640268,
    "created_at_ist": "Thursday - Oct 13, 2022",
    "updated_at_ist": "Thursday - Oct 13, 2022"
  },
  {
    "id": 69,
    "title": "French Fries with Sausages",
    "creator_name": "Vance Connelly",
    "creator_email": "[email protected]",
    "created_at": "2022-10-13 05:51:08 UTC",
    "updated_at": "2022-10-13 05:51:08 UTC",
    "created_at_epoch": 1665640268,
    "updated_at_epoch": 1665640268,
    "created_at_ist": "Thursday - Oct 13, 2022",
    "updated_at_ist": "Thursday - Oct 13, 2022"
  },
  {
    "id": 3,
    "title": "Pork Belly Buns",
    "creator_name": "Mrs. Willie Green",
    "creator_email": "[email protected]",
    "created_at": "2022-10-13 05:51:08 UTC",
    "updated_at": "2022-10-13 05:51:08 UTC",
    "created_at_epoch": 1665640268,
    "updated_at_epoch": 1665640268,
    "created_at_ist": "Thursday - Oct 13, 2022",
    "updated_at_ist": "Thursday - Oct 13, 2022"
  },
  {
    "id": 4,
    "title": "Peking Duck",
    "creator_name": "Joselyn VonRueden",
    "creator_email": "[email protected]",
    "created_at": "2022-10-13 05:51:08 UTC",
    "updated_at": "2022-10-13 05:51:08 UTC",
    "created_at_epoch": 1665640268,
    "updated_at_epoch": 1665640268,
    "created_at_ist": "Thursday - Oct 13, 2022",
    "updated_at_ist": "Thursday - Oct 13, 2022"
  },
  {
    "id": 5,
    "title": "Hummus",
    "creator_name": "Stacee Pfannerstill",
    "creator_email": "[email protected]",
    "created_at": "2022-10-13 05:51:08 UTC",
    "updated_at": "2022-10-13 05:51:08 UTC",
    "created_at_epoch": 1665640268,
    "updated_at_epoch": 1665640268,
    "created_at_ist": "Thursday - Oct 13, 2022",
    "updated_at_ist": "Thursday - Oct 13, 2022"
  },
  {
    "id": 6,
    "title": "California Maki",
    "creator_name": "Fidel Schroeder",
    "creator_email": "[email protected]",
    "created_at": "2022-10-13 05:51:08 UTC",
    "updated_at": "2022-10-13 05:51:08 UTC",
    "created_at_epoch": 1665640268,
    "updated_at_epoch": 1665640268,
    "created_at_ist": "Thursday - Oct 13, 2022",
    "updated_at_ist": "Thursday - Oct 13, 2022"
  },
  {
    "id": 7,
    "title": "French Toast",
    "creator_name": "Alvaro Berge",
    "creator_email": "[email protected]",
    "created_at": "2022-10-13 05:51:08 UTC",
    "updated_at": "2022-10-13 05:51:08 UTC",
    "created_at_epoch": 1665640268,
    "updated_at_epoch": 1665640268,
    "created_at_ist": "Thursday - Oct 13, 2022",
    "updated_at_ist": "Thursday - Oct 13, 2022"
  },
  {
    "id": 8,
    "title": "Arepas",
    "creator_name": "Alva Kris DO",
    "creator_email": "[email protected]",
    "created_at": "2022-10-13 05:51:08 UTC",
    "updated_at": "2022-10-13 05:51:08 UTC",
    "created_at_epoch": 1665640268,
    "updated_at_epoch": 1665640268,
    "created_at_ist": "Thursday - Oct 13, 2022",
    "updated_at_ist": "Thursday - Oct 13, 2022"
  },
  {
    "id": 9,
    "title": "Meatballs with Sauce",
    "creator_name": "Willie Kuhic",
    "creator_email": "[email protected]",
    "created_at": "2022-10-13 05:51:08 UTC",
    "updated_at": "2022-10-13 05:51:08 UTC",
    "created_at_epoch": 1665640268,
    "updated_at_epoch": 1665640268,
    "created_at_ist": "Thursday - Oct 13, 2022",
    "updated_at_ist": "Thursday - Oct 13, 2022"
  }
]

Benchmark, rails 7.0.2.3, ruby 3.0.3


  # there are 1100 posts in the DB, having fields 
  # :id, :title, :content, :creator_name, :creator_email, :created_at, :updated_at
  posts = Post.all
  s = PostSerializer.new(posts)

  n = 1000
  Benchmark.bm do |x|
    x.report("ActiveModel Serializer") { n.times { posts.to_json } }
    x.report("JSON:API Serialization") { n.times { PostJsonapiSerializer.new(posts).serializable_hash.to_json }}
    x.report("Blueprinter")            { n.times { PostBlueprint.render(posts) }}
    x.report("FastJsonSerializer")     { n.times { s.serialized_json } }
  end

  # result
  user                    system      total         real
  ActiveModel Serializer  35.373407   0.000000      35.373407 ( 35.380744)
  JSON:API Serialization  50.476935   0.043584      50.520519 ( 50.546082)
  Blueprinter             20.458713   0.000000      20.458713 ( 20.484488)
  FastJsonSerializer       5.239119   0.015989       5.255108 (  5.256627)

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/skarmakar/fast-json-serializer.