Deprecated v 0.2 Readme (does not work with 0.3.0)

fabrik42 edited this page Feb 24, 2011 · 1 revision

deprecated acts_as_api 0.2 Readme (does not work with 0.3.0)

DESCRIPTION:

acts_as_api makes creating XML/JSON responses in Rails 3 easy and fun.

FEATURES:

The built-in XML/JSON support of Rails is great but:

You surely don't want to expose your models always with all attributes.

acts_as_api enriches the models and controllers of your app in a rails-like way so you can easily determine how your API responses should look like.

acts_as_api uses the *default Rails serializers* for XML and JSON, so you don't have to mess around with even more dependencies. Once you change the serializers for your Rails app, they will be changed for acts_as_api too.

As of the version 0.2.0 it supports multiple api rendering templates for a models. This is especially useful for API versioning or for example for private vs. public access points to a user's profile.

*Note that upgrading to 0.3.0 will break code that worked with previous versions due to a complete overhaul of the lib*

SYNOPSIS:

Set up your model

Say you have a model Customer and every customer has many Orders.

If you only want to expose the firstname and lastname attribute of a customer via the api, you would do something like this:

class Customer < ActiveRecord::Base

  has_many :orders

  # let this model act as api!
  acts_as_api

  # define the accessible attributes/methods for the api response
  api_accessible :default => [ :firstname, :lastname ]

end

An API template with the name :default was created, see below how to use it in the controller:

Set up controller

Now you just have to exchange the render method in your controller for the render_for_api method.

class CustomersController < ApplicationController

  def show
    @customer = Customer.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
      format.xml   { render_for_api :default, :xml  => @customer }
      format.json  { render_for_api :default, :json => @customer }
    end
  end

end

That's it!

Try it. The response should now look like this:

<?xml version="1.0" encoding="UTF-8"?>
<customer>
  <firstname>John</firstname>
  <lastname>Doe</lastname>
</customer>

Other attributes of the model like created_at or updated_at won't be included because they were not listed by api_accessible in the model.

But you can do more…

API Versioning

With the different named API templates, API versioning is pretty easy:

class User < ActiveRecord::Base

  # let this model act as api!
  acts_as_api

  # define the accessible attributes/methods for the api response
  api_accessible
    :v1_public  => [ :firstname, :age ],
    :v2_public  => [ :firstname, :age, :sex ],

    :v1_private => [ :firstname, :lastname, :age, :sex ],
    :v2_private => [ :firstname, :lastname, :age, :sex, :phone ]

end

Now you could create a method in the application controller of your app:

def api_template(version = :v2, template = :public)
  "#{version.to_s}_#{template.to_s}".to_sym
end

And render the API responses:

class UsersController < ApplicationController

  # renders the :v2_public template
  def show
    @user = User.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb        
      format.xml   { render_for_api api_template, :xml  => @user }
      format.json  { render_for_api api_template, :json => @user }
    end
  end

  # renders the :v1_private template
  def profile_deprecated
    @user = @current_user

    respond_to do |format|
      format.html # show.html.erb        
      format.xml   { render_for_api api_template(:v1, :private), :xml  => @user }
      format.json  { render_for_api api_template(:v1, :private), :json => @user }
    end
  end

end

Metadata

You can include metadata elements in the response outside of your objects and collections. Typical usage for this is to include a total results count or page. Just pass in a :meta key with a hash of the meta items you want.

class CustomersController < ApplicationController

  def index
    @customers = Customer.paginate(:all, :page = params[:page])
    metadata = { :total => @customers.total_entries, :page => params[:page] }
    respond_to do |format|
      format.html # show.html.erb
      format.xml   { render_for_api :default, :xml  => @customer, :meta => metadata }
      format.json  { render_for_api :default, :json => @customer, :meta => metadata }
    end
  end

end

What can I include in my responses?

You can do basically anything:

  • Include attributes and all other kinds of methods of your model

  • Include child associations (if they also act_as_api this will be considered)

  • Call methods of a parent association

  • Rename attributes, methods, associations

  • Create your own hierarchies

Here are two models from the example app that show how it works.

The model Customer shows all kinds of ways to add data to your API response.

class Customer < ActiveRecord::Base

  has_many :orders

  # let this model act as api!
  acts_as_api

  # define the accessible attributes/methods for the api response
  # some attributes of the model
  api_accessible :default => [ :firstname, :lastname, :age,
    # you can include methods
    :full_name,
    # include associated model in response
    :orders,
    # rename the node for orders
    { :renamed_orders => :orders },
    # put orders in another subnode
    { :subnode_orders =>  { :sub_oders => :orders } },
    # rename nodes/tag names
    { :other_node => :say_something },
    # create a deeper node hierarchy
    { :maybe => { :useful => { :for => :say_something } } }
  ]

  # some example methods
  def full_name
    '' << firstname.to_s << ' ' << lastname.to_s
  end

  def say_something
    "something"
  end

end

The model Order also acts as api and is even able to access a method of their parent customer.

class Order < ActiveRecord::Base

  belongs_to :customer

  # let this model act as api!
  acts_as_api

  # define the accessible attributes/methods for the api response
  # some attributes of the model
  api_accessible :default => [ :city, :amount,
  #access a method of the parent association
    { :parent_name => "customer.full_name" }
  ]

end

Is there an example I can play around with?

If you want a working example right out of the box, grab the example app: github.com/fabrik42/acts_as_api_example

REQUIREMENTS:

  • Rails 3.0.0

INSTALL:

sudo gem install acts_as_api

Then add acts_as_api to the Gemfile of your Rails project

gem 'acts_as_api'

Links

LICENSE:

(The MIT License)

Copyright © 2010 Christian Bäuerlein

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.