JSONBuilder

JSONBuilder is to JSON as Builder is to XML

Installation

Add the following line to your application's Gemfile:

gem 'json_builder'

And then run:

$ bundle install

Or install it yourself with:

$ gem install json_builder

Sample Usage

require 'json_builder'

json = JSONBuilder::Compiler.generate do
  name 'Garrett Bjerkhoel'
  email 'spam@garrettbjerkhoel.com'
  url root_path
  address do
    street '1234 1st Ave'
    street2 'Apt 1'
    city 'New York'
    state 'NY'
    zip 10065
  end
  key :nil, 'testing a custom key name'
  skills do
    ruby true
    asp false
  end
  longstring do
    # Could be a highly intensive process that only returns a string
    '12345' * 25
  end
end

Which will generate:

{
  "name": "Garrett Bjerkhoel",
  "email": "spam@garrettbjerkhoel.com",
  "url": "/",
  "address": {
    "street": "1234 1st Ave",
    "street2": "Apt 1",
    "city": "New York",
    "state": "NY",
    "zip": 10065
  },
  "nil": "testing a custom key name",
  "skills": {
    "ruby": true,
    "asp": false
  },
  "longstring": "1234512345123451234512345..."
}

If you'd like to just generate an array:

array ['Garrett Bjerkhoel', 'John Doe'] do |name|
  first, last = name.split(' ')
  first first
  last last
end

Which will return:

[
  {
    "first": "Garrett",
    "last": "Bjerkhoel"
  },
  {
    "first": "John",
    "last": "Doe"
  }
]

Just a note, if you use an array block as above, all other sibling method calls will be ignored.

Using JSONBuilder with Rails

To use JSONBuilder with your Rails application, make sure your controller responds to json:

class UsersController < ApplicationController
  respond_to :json

  def index
    @users = User.order('id DESC').page(params[:page]).per(2)
    respond_with @users
  end
end

Then create your view app/views/users/index.json.json_builder which could look something like:

count @users.count
page @users.current_page
per_page @users.per_page
pages_count @users.num_pages
results @users do |user|
  id user.id
  name user.name
  body user.body
  url user_url(user)
  links user.links do |link|
    url link.url
    visits link.visits
    last_visited link.last_visited
  end
end

The response that is returned:

{
  "count": 10,
  "page": 1,
  "per_page": 2,
  "pages_count": 5,
  "results": [
    {
      "id": 1,
      "name": "Garrett Bjerkhoel",
      "body": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod.",
      "url": "http://example.com/users/garrett-bjerkhoel",
      "links": [
        {
          "url": "http://github.com/",
          "visits": 500,
          "last_visited": "2011-11-271T00:00:01Z"
        },
        {
          "url": "http://garrettbjerkhoel.com/",
          "visits": 1500,
          "last_visited": "2011-11-261T00:00:01Z"
        }
      ]
    }, {
      "id": 2,
      "name": "John Doe",
      "body": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod.",
      "url": "http://example.com/users/john-doe",
      "links": [
        {
          "url": "http://google.com/",
          "visits": 11000,
          "last_visited": "2010-05-221T00:00:01Z"
        },
        {
          "url": "http://twitter.com/",
          "visits": 155012857,
          "last_visited": "2011-11-261T00:00:01Z"
        }
      ]
    }
  ]
}

Including JSONP callbacks

Out of the box JSONBuilder supports JSONP callbacks when used within a Rails project just by using the callback parameter. For instance, if you requested /users.json?callback=myjscallback, you'll get a callback wrapping the response:

myjscallback([
  {
    "name": "Garrett Bjerkhoel"
  },
  {
    "name": "John Doe"
  }
])

To turn off JSONP callbacks globally or just per-environment:

Globally

ActionView::Base.json_callback = false

Per Environment

Sample::Application.configure do
  config.action_view.json_callback = false
end

Pretty Print Output

Out of the box JSONBuilder supports pretty printing only during development, it's disabled by default in other environments for performance. If you'd like to enable or disable pretty printing you can do it within your environment file or you can do it globally.

With pretty print on:

{
  "name": "Garrett Bjerkhoel",
  "email": "spam@garrettbjerkhoel.com"
}

Without:

{"name": "Garrett Bjerkhoel", "email": "spam@garrettbjerkhoel.com"}

Per Environment

Sample::Application.configure do
  config.action_view.pretty_print_json = false
end

Globally

ActionView::Base.pretty_print_json = false

Speed

JSONBuilder is very fast, it's roughly 3.6 times faster than Builder based on the speed benchmark.

             user       system      total       real
JSONBuilder  2.950000   0.010000    2.960000    (2.968790)
    Builder  10.820000  0.040000    10.860000   (10.930497)

Alternative libraries

There are alternatives to JSONBuilder, each good in their own way with different API's and design approaches that are worth checking out. Although, I would love to hear why JSONBuilder didn't fit your needs, by message or issue.

Copyright

Copyright © 2012 Garrett Bjerkhoel. See MIT-LICENSE for details.