Rails API’s – Rendering Flexible XML and JSON

When creating API’s, you want to make it so people can easily make remote requests and in return be given well structured data. Here I discuss why Rails to_json and to_xml methods don’t quite cut it, and what to do instead.

to_json is not always flexible enough

As expertly explained in this post, the Rails helper method “to_json” is not optimal when producing public API’s. Right now I am adjusting the Quick Timesheets API to meet our clients needs, which pretty much involves gutting my lazy “to_xml” and “to_json” calls and replacing them something that renders the xml elements and json attribute I need.

My case is perhaps more complicated than usual because the object I want to render as xml is complex and not tied to any Active Record object. It is the result of a complex search (searching time entries) and is a ruby struct containing all the information I need to render the search results view.

Use builder to create the xml, then convert the xml to json

Anyway, my way of doing it was to use the builder gem to create the xml, as explained nicely here, and then for json I used the crack gem to help convert the xml generated from builder into json.

# times_controller
require 'crack'

def search
  @data = get_data
  respond_to do |format|
    format.html {redirect_to :action => :index}
    format.js
    format.xml
    format.json { render :json => Crack::XML.parse(render_to_string(:template => "times/search.xml.builder", :layout => false)).to_json }
  end
end

# search.xml.builder
xml.instruct!
xml.results do
  xml.total_entries @data.total_entries
  xml.error @data.error
  xml.days @data.days
  xml.total_hours @data.total_hours
  xml.totals_by_type do
    @data.totals_by_type.each do |k,v|
      xml.type do
        xml.name v[0]
        xml.id k
        xml.total v[1]
        xml.percentage v[2]
      end
    end
  end
  xml.start_date @data.start_date
  xml.end_date @data.end_date
  xml.clients do
    @data.clients.each do |client|
      xml.client do
        xml.name client.name
        xml.users do
# etc.. you get the gist!

If your data is tightly coupled with your ActiveRecord objects, I recommend you use the RABL gem.

Note that I did check out the Tokamak gem but found it slightly lacking in Documentation.

Tagged: , , ,

About the Author

Plattsi | Other Articles

A twenty something web developer and entrepreneur from Sydney, Australia. Loves building web applications that are both easy and fun to use (and don't require manuals).

  • http://padrinorb.com/ Nathan Esquenazi

    Glad to see another person who is removing to_json and moving to a more robust (representation / view centered) API approach. Since I wrote RABL, I have consistently been glad to be rid of to_json from my code. I find keeping the API representations tucked neatly into views (akin to html) has been consistently easier to manage and maintain. I can see using builder for your case and in the case of needing APIs that are *not* coupled to ORM objects in JSON, I would recommend checking out https://github.com/bsiggelkow/jsonify

  • http://webtempest.com Web Tempest

    How did I miss jsonify?? Google fail. Cheers