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.

blockquote.code {
font-style: normal;
font-family: Monaco,monospace;
font-size: 12px;
border: solid 1px #aaa;
padding: 6px;
background-color: #eee;
color: inherit;
overflow:auto;
margin: 10px 0px;
}

Create

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>

Index

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>

Show

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>

Update

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

5 thoughts on “simple web services with rails

  1. Is there a way to actually do this in your functional test rather than using curl? In other words, rather than calling:

    post :create, params

    Can we call something like:

    post :create, :xml => (object.to_xml)?

    That would be nice just so we can jump into a functional test and look at the response.body for debugging.

    Thanks,
    Tom

  2. I absolutely agree that this kind of thing belongs in your test suite. Thanks for pointing that out. I’m fond of cucumber for testing this kind of thing (since it also provides docs for the APIs that you could give to another developer). However, I did this because my tests were failing when they used to succeed and I didn’t understand why… it turned out that there was some syntax change in a version upgrade that led to the http header not being set correctly. In any case, I found that getting back to basics helped me isolate the issue.

  3. This method of testing with cron is definitely valuable! I was just wondering how I could test (preferably without a plugin). It would seem like with all the emphasis on REST and on testing, that the framework would make it a little easier to test something like your app responding to an xml post.

  4. Many thanks from a Rails noob.
    Your write-up helped me solve a problem I was having with POSTing XML to a
    Rails 3.0 app I’m developing.

  5. I’m new to Rails and plans eventually include providing web services from/to a simple Rails app. I’m amazed at what you’ve described here. You’re issuing your curl commands on the same machine that’s running Rails. Can you point me to a good resource that covers “getting in the door” to Rails from another machine to issue equivalent commands? Thanks much!

    Ed
    Philadelphia

What do you think?