Web Services
Exposing an API
APIs are becoming an essential feature of modern web applications. Rails does a good job of helping your application provide an API using the same MVC structure you are accustomed to.
Use the Blogger sample application to complete the exercises in this section. See the Setup Instructions for help.
In the Controller
Here is an example controller:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
We decide to service JSON and XML requests from these two actions. The index will be triggered by a GET request to /articles.json or /articles.xml. The create will be triggered by a POST request to the same paths.
respond_to
The first step is to call respond_to and list the formats our controller will respond to. This is typically done at the beginning of the controller:
1 2 3 4 | |
Our controller will now attempt to respond to requests for HTML, JSON, or XML.
When starting out with an API, I often forget the :html in the respond_to. The application will work at first because it will match an existing view template for the rendering. But, once you start using respond_with, your responses will be blank unless you include :html here.
If you request /articles.json you will find that the application is still unsuccessfully trying to render articles.json.erb.
respond_with
You could write a view template for JSON and one for XML, but doing so is a tremendous pain. Instead, we would like to render the data directly from the controller.
Simple Rendering
In the past, we broke down each format response using respond_to in the controller action:
1 2 3 4 5 6 7 8 | |
It led to a lot of repetition. In Rails 3, we can instead use respond_with:
1 2 3 4 | |
The respond_with method will first attempt to render a matching view template for the response type, like index.json.erb or index.html.erb. If that template is not found, then the method will call .to_xml or .to_json on the object and render the result.
By combining respond_to and respond_with we can save a lot of boilerplate code that was prevalent in Rails 2.
Object Validation
But how is this technique used when we write a create action that checks object validation? We started with this:
1 2 3 4 5 6 7 8 9 | |
We can achieve the same functionality using respond_with:
1 2 3 4 5 6 7 8 9 | |
Then refactoring the branch into a ternary:
1 2 3 4 5 | |
When we pass @article to respond_with, it will actually check if the object is valid? first. If the object is not valid, then it will call render :new when in a create or render :edit when in an update.
If the object is valid, it will automatically redirect to the show action for that object.
Controlling the Redirect
Maybe you would rather redirect to the index after successful creation. You can override the redirect by adding the :location option to respond_with:
1 2 3 4 5 | |
Overriding by Format
Does that action feel too simple? Would you like to bring back some of the heavy syntax from Rails 2? Then specify the response by output format:
1 2 3 4 5 6 7 8 9 | |
Filtering Data
When you use respond_with to output JSON or XML, it will, by default, dump all the attributes. Next we will look at how to filter these attributes from the model layer.
Exercises
- Modify
ArticlesControllerso all actions userespond_withand can speak JSON and HTML. - Make similar changes to
CommentsControllerso comments can be read and written via JSON. - CHALLENGE: Use http-console (https://github.com/cloudhead/http-console) to interact with the application using JSON
Resources
ActionController::ResponderAPI: http://api.rubyonrails.org/classes/ActionController/Responder.html- AsciiCast on Rails 3 Controllers: http://asciicasts.com/episodes/224-controllers-in-rails-3
- PlatformaTec posts on
respond_with: http://blog.plataformatec.com.br/tag/respond_with/