Skip to content

22 API Jbuilder Views

Dave Strus edited this page Jul 18, 2015 · 1 revision

Jbuilder Views

Let's look again at our new controller.

app/controllers/api/v1/notes_controller.rb

class API::V1::NotesController < ApplicationController
  def index
    @notes = Note.all
    respond_to do |format|
      format.json do
        render json: @notes.to_json
      end
    end
  end
end

@notes.to_json will take all attributes of the note and render them out in the response as JSON objects. What if we added a migration to add, remove, or rename a column? Then the JSON output could change, which may break applications that are consuming that API.

Rails now ships with a gem named jbuilder that makes it easier to map Ruby objects to JSON structures in a way that, even if we update the model, the JSON "views" won't change.

Let's add a jbuilder view for api/v1/notes#index in app/views/api/v1/notes/index.json.jbuilder:

json.array!(@notes) do |note|
  # json.extract! note, :id, :title, :body_text, :body_html, :created_at, :updated_at
  # is equivalent to this, but I like this better.
  json.id note.id
  json.title note.title
  json.body_text note.body_text
  json.body_html note.body_html
  json.created_at note.created_at
  json.updated_at note.updated_at
  json.url api_v1_note_url(note, format: :json)
end

Note the json.extract! takes the note object, and an array of symbols that correspond to the columns we want to display. If those columns do change, then the json may not have a value for that anymore, but it will still include the JSON key in the response with that name. We've commented this line out, as we are going to specify our JSON keys and values one-at-a-time.

In addition to the normal attributes, note the custom attribute json.url that we've included to link to the URL for the object. This is a technique used for "disoverable" API's (sometimes called HyperMedia). This makes it apparent to an API consumer where it can go to get more information.

Now that the view is in place, we can remove the render json: @notes.to_json block from the controller action. Without a render or redirect_to, Rails will simply look for the appropriate view to render.

app/controllers/api/v1/notes_controller.rb

def index
  @notes = Note.all
  respond_to do |format|
    format.json
  end
end

Since we're responding only to .json, we can also pass respond_to a symbol instead of a block: app/controllers/api/v1/notes_controller.rb

def index
  @notes = Note.all
  respond_to :json
end

Now our JSON should look really nice.

Lab

Make a show method for api/v1/notes_controller with a reasonable .jbuilder template, much like the index action.