<!-- .entry-meta -->
Rails enables web services by default, which is pretty awesome, and I’ve been relying on that for a while. It is pretty nifty how Rails will magically parse XML post parameters, create an in-memory object and then save that object to the database without your having to write one line of code. However, when the magic fails it can be pretty hard to debug. I found it useful to run basic tests on the command line using curl (hearing the voice of Zach Moazeni in my head saying: “test your assumptions.”)
Below is a writeup of the set of curl commands and sample output for testing the default Rails XML REST APIs. This can serve as a cheat sheet for the experienced or an introduction for folks new to rails who want a basic understanding of the default webservice APIs.
Create an app, by typing the following commands into your terminal:
$ rails basic_app
$ cd basic_app
$ ./script/generate scaffold project title:string description:text
$ rake db:migrate
$ ./script/server
In Rails 2.3, you also need to added the following line to the top of app/controllers/projects_controller.rb (This will allow external access to the APIs.) You can make this change while the server is running, btw.
skip_before_filter :verify_authenticity_token
Leave that window open where you can see it, since it will output useful stuff from the log. Then in another terminal window, experiment with the following commands to interact with your application APIs.
POST /projects.xml
Create a project object based on the XML representation given in the post body and save in the projects database table.
$ curl -X POST -d "<project><title>Awesome</title><description>This is an awesome project.</description></project>" -H "Content-Type: application/xml" http://localhost:3000/projects.xml
<?xml version="1.0" encoding="UTF-8"?>
<project>
<created-at type="datetime">2009-06-21T10:13:43-07:00</created-at>
<description>This is an awesome project.</description>
<id type="integer">6</id>
<title>Awesome</title>
<updated-at type="datetime">2009-06-21T10:13:43-07:00</updated-at>
</project>
GET /projects.xml
This returns a list of all of the projects in the database with an automatically generated XML representation.
$ curl http://localhost:3000/projects.xml<?xml version="1.0" encoding="UTF-8"?>
<projects type="array">
<project>
<created-at type="datetime">2009-06-21T10:13:19-07:00</created-at>
<description>This is an awesome project.</description>
<id type="integer">1</id>
<title>Awesome</title>
<updated-at type="datetime">2009-06-21T10:13:19-07:00</updated-at>
</project>
<project>
<created-at type="datetime">2009-06-21T10:13:43-07:00</created-at>
<description>New information here</description>
<id type="integer">2</id>
<title>Awesome</title>
<updated-at type="datetime">2009-06-21T10:49:21-07:00</updated-at>
</project>
</projects>
GET /projects/1.xml
This returns an xml representation of the project with id #1
$ curl http://localhost:3000/projects/1.xml<?xml version="1.0" encoding="UTF-8"?>
<project>
<created-at type="datetime">2009-06-21T10:45:19-07:00</created-at>
<description>This is an awesome project.</description>
<id type="integer">8</id>
<title>Awesome</title>
<updated-at type="datetime">2009-06-21T10:45:19-07:00</updated-at>
</project>
PUT /projects/1.xml
This modifies the project with id #1
curl -X PUT -d "<project><description>New information here</description></project>" -H "Content-Type: application/xml" http://localhost:3000/projects/1.xml
If you’re anything like me, you’ve used cURL to download a batch of MP3 files from the web, or to move a TAR file from one remote server to another. It might come as a surprise, then, that cURL is a full-featured HTTP client, which makes it perfect for interacting with RESTful web services like the ones encouraged by Rails 2. To illustrate, let’s create a small Rails app called ‘tv_show’:
rails tv_show cd tv_show script/generate scaffold character name:string action:string rake db:migrate script/server
Fire up your web browser and create a few characters. Once you’ve done that, open a new terminal window and try the following:
curl http://localhost:3000/characters.xml
You’ll get a nice XML representation of your characters:
<?xml version"1.0" encoding="UTF-8"?> <characters type="array"> <character> <id type="integer">1</id> <name>George Sr.</name> <action>goes to jail</action> <created-at type="datetime">2008-03-28T11:01:57-04:00</created-at> <updated-at type="datetime">2008-03-28T11:01:57-04:00</updated-at> </character> <character> <id type="integer">2</id> <name>Gob</name> <action>rides a Segway</action> <created-at type="datetime">2008-03-28T11:02:07-04:00</created-at> <updated-at type="datetime">2008-03-28T11:02:12-04:00</updated-at> </character> <character> <id type="integer">3</id> <name>Tobias</name> <action>wears cutoffs</action> <created-at type="datetime">2008-03-28T11:02:20-04:00</created-at> <updated-at type="datetime">2008-03-28T11:02:20-04:00</updated-at> </character> </characters>
You can retrieve the representation of a specific character by specifying his ID in the URL:
dce@roflcopter ~ > curl http://localhost:3000/characters/1.xml <?xml version="1.0" encoding="UTF-8"?> <character> <id type="integer">1</id> <name>George Sr.</name> <action>goes to jail</action> <created-at type="datetime">2008-03-28T11:01:57-04:00</created-at> <updated-at type="datetime">2008-03-28T11:01:57-04:00</updated-at> </character>
To create a new character, issue a POST request, use the -X flag to specify the action, and the -d flag to define the request body:
curl -X POST -d "character[name]=Lindsay&character[action]=does+nothing" http://localhost:3000/characters.xml
Here’s where things get interesting: unlike most web browsers, which only support GET and POST, cURL supports the complete set of HTTP actions. If we want to update one of our existing characters, we can issue a PUT request to the URL of that character’s representation, like so:
curl -X PUT -d "character[action]=works+at+clothing+store" http://localhost:3000/characters/4.xml
If we want to delete a character, issue a DELETE request:
curl -X DELETE http://localhost:3000/characters/1.xml
For some more sophisticated uses of REST and Rails, check out rest-client and ActiveResource.