Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Rails provides an excellent XML Builder by default to build RSS and ATOM feeds, but nothing to help you build complex and custom JSON data structures. JSON Builder is here to help.

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.
lib
test
.gitignore
Gemfile
Gemfile.lock
MIT-LICENSE
README.md
Rakefile
json_builder.gemspec

README.md

JSON Builder Build Status

Rails provides an excellent XML Builder by default to build RSS and ATOM feeds, but nothing to help you build complex and custom JSON data structures. The standard to_json works just fine, but can get very verbose when you need full control of what is generated and performance is a factor. JSON Builder hopes to solve that problem.

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 output the following:

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

Just a note, if you use an array block, all other builder methods will be ignored.

Using JSON Builder with Rails

First, make sure to add the gem to your Gemfile.

gem 'json_builder'

Second, 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

Lastly, create app/views/users/index.json_builder which could look something like:

count @users.count
current_page @users.current_page
per_page @users.per_page
num_pages @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

You will get something like:

{
  "total": 10,
  "page": 1,
  "per_page": 2,
  "total_pages": 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 JSON Builder 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 be able to turn off this functionality, you can do it per-environment, or globally:

Per Environment

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

Globally

ActionView::Base.json_callback = false

Pretty Print Output

Out of the box JSON Builder supports pretty printing the JSON for the development environment, the rest have it turned off for performance reasons. 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

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

Globally

ActionView::Base.pretty_print_json = false

Speed

JSON Builder is very fast, it's roughly 3.6 times faster than the core XML 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)

Other JSON Builders

There are quite a few other alternatives to JSON Builder, each good in their own way with different DSL's and design approaches that are worth checking out:

Note on Patches/Pull Requests

  • Fork the project.
  • Make your feature addition or bug fix.
  • Add tests for it. This is important so I don't break it in a future version unintentionally.
  • Commit, do not mess with Rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself in another branch so I can ignore when I pull)
  • Send me a pull request. Bonus points for topic branches.

Copyright

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

Something went wrong with that request. Please try again.