Interact with REST Services from the Command Line

REST is becoming more popular as a means of implementing Service Oriented Architectures (SOA) as well as merely providing simple remote APIs for interacting with systems. The main reason for this is that it provides a very simple means of creating and consuming Services. Contrasted to SOA implementations like SOAP and REST can be a relief of simplicity.

One of the main advantages of REST is that it requires no tooling to use. Unlike SOAP, it is very easy to construct ad-hoc clients to consume a RESTful service. These examples use curl a command-line utility available on Unix systems or using Cygwin on Windows. The same concepts can be translated to anything that can send HTTP requests.

Example REST Service with Ruby on Rails

As the example implementation, I’ll use a Ruby on Rails controller. Rails has very good support for implementing RESTful services so is easy to show.

To get started with this example you can generate a Rails project and the Order object with the following commands:

rails order_example
cd order_example
./script generate resource order name:string

Then you can implement a RESTful controller with the following code:

class OrdersController < ApplicationController # GET /orders # GET /orders.xml def index @orders = Order.find(:all) respond_to do |format| format.html # index.rhtml format.xml { render :xml => @orders.to_xml }
end
end

# GET /orders/1
# GET /orders/1.xml
def show
@order = Order.find(params[:id])
respond_to do |format|
format.html # index.rhtml
format.xml { render :xml => @order.to_xml }
end
end

# POST /orders
# POST /orders.xml
def create
@order = Order.new(params[:order])
respond_to do |format|
if @order.save
flash[:notice] = 'Order was successfully created.'
format.html { redirect_to order_url(@order) }
format.xml { head :created, :location => order_url(@order) }
else
format.html { render :action => "new" }
format.xml { render :xml => @order.errors.to_xml }
end
end
end

# PUT /orders/1
# PUT /orders/1.xml
def update
@order = Order.find(params[:id])
respond_to do |format|
if @order.update_attributes(params[:order])
flash[:notice] = 'Order was successfully updated.'
format.html { redirect_to order_url(@order) }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => @order.errors.to_xml }
end
end
end

# DELETE /orders/1
# DELETE /orders/1.xml
def destroy
@order = Order.find(params[:id])
@order.destroy
respond_to do |format|
format.html { redirect_to orders_url }
format.xml { head :ok }
end
end
end

This controller allows you respond to all of the Actions that can be taken on a Resource: GET, POST, PUT and DELETE.

Command Line Interaction with the Service

Start our Rails application and then you can see the following commands at work.

./script/server

Get a list of all of the Orders

The first thing you want to do is get a list of all of the orders in the system. To do this we perform a GET command asking for an XML response. The URI in this case represents a list of all the Orders in the system.

curl -X GET -H 'Accept: application/xml' http://localhost:3000/orders

Get a single Order

If we want to get the XML representation of a single order then we can ask for a specific Order by changing the ID to a URI that represents just one Order.

curl -X GET -H 'Accept: application/xml' http://localhost:3000/orders/15

Delete an Order

REST keeps things simple by having consistent Resource URIs. The URI that represents Order number 15 can also be used to Delete or Modify that Order. In this case the URI for the GET is the same, but we ask it to delete the Order instead.

curl -X DELETE -H 'Accept: application/xml' http://localhost:3000/orders/15

Modify an existing Order

Just as with delete, if we want to modify an Order we use the URI that represents that specific Order. The only difference is that we have to tell the server that we are sending it XML, and then actually send the XML.

curl -i -X PUT -H 'Content-Type: application/xml' -H 'Accept: application/xml' \
-d 'Foo' http://localhost:3000/orders/15

Create a new Order

Creating an Order looks very similar to modifying an Order but the URI changes to the Resource URI for the collection of all Orders. The response to this command will be an HTTP 302 Redirect that gives you the URI of the newly created Order Resource.

curl -i -X POST -H 'Content-Type: application/xml' -H 'Accept: application/xml' \
-d 'Foo' http://localhost:3000/orders/

Conclusion

I think you can see how easily you can interact with a REST service using only the most basic tools available, namely simple Unix command line utilities. This simplicity offers a lot of power, flexibility and interoperability that you lose when you implement services with more complicated implementations such as SOAP. That’s not to say that SOAP and all of the WS-* specifications don’t have have their place, because they do. When you can implement a simple solution and meet your needs you will often find that solution to have a surprising amount of added benefits such as flexibility.

Rails on Rails

If Ruby on Rails is all about optimizing the development of web applications, then what would happen if you optimized Rails?

Well, it would get streamlined. Streamlined is a generator for Rails that can be used to easily create sites that are much better looking and much easier to use than the standard scaffold generated views. Even if you wouldn’t want to use it to create the full site, it might be useful to generate an administrative section that would have a much more limited audience.

The other interesting thing about Streamlined is that it does for views what Rails already has for the Model objects. In Rails Model objects, you can use a declarative syntax to decorate the object to define relationships and to override behavior. With Streamlined you can do the same thing with views. You don’t have to edit HTML or rHTML templates, you can just decorate some generated classes to override the default behavior.

In the spirt of Rails, there’s a great screencast available at the site showing off some of these really interesting features. Check it out…

(Thanks to the Milwaukee Ruby User’s Group for showing the screencast.)