Showing posts with label API. Show all posts
Showing posts with label API. Show all posts

Tuesday, January 24, 2012

REST - Taking a Closer Look (Part 5)

In this post, we'll take a closer look at the update process using PUT with the Grails project.   REST defines updates as a HTTP PUT method.

First we need to make a few adjustments to the code to make the update operation respond to the PUT method and alter the edit form to ensure it is sending in a method of PUT.

Alter the allowedMethods array to recognize PUT for the update method.

Alter the form method to ensure it sends PUT as the method.
Now that we have ensured the method is set to PUT on the form and the controller will accept PUT as the method from the client let's test.  (After selecting a specific book, click the Edit button along the bottom of the view.)  Altering some data and clicking the Update button we should be in business to see the transaction.  The following screenshot details the HTTP headers transferred during the state transition.
Here we can see that the request was actually done using POST.  Internally within the request parameters a PUT method is specified.  This is detailed further in the Grails 2.0.0 documentation.
Issuing a request with a method other than GET or POST from a regular browser is not possible without some help from Grails.
This doesn't seem to be consistent with the REST architecture or the HTTP v1.1 specification.  Grails is also blocking a method of PUT coming from the browser with a 405 - Method Not Allowed response.  Requests made with cUrl go through without error.
$ curl --request PUT http://localhost:8080/research-grails-rest/book/update/1 --verbose
* About to connect() to localhost port 8080 (#0)
*   Trying ::1... connected
* Connected to localhost (::1) port 8080 (#0)
> PUT /research-grails-rest/book/update/1 HTTP/1.1
> User-Agent: curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5
> Host: localhost:8080
> Accept: */*
>
< HTTP/1.1 302 Moved Temporarily
< Server: Apache-Coyote/1.1
< Set-Cookie: JSESSIONID=F91DEA3433A1F745B249C0F7E3E9988E; Path=/research-grails-rest/; HttpOnly
< Location: http://localhost:8080/research-grails-rest/book/show/1
< Content-Length: 0
< Date: Tue, 24 Jan 2012 10:45:05 GMT
<
* Connection #0 to host localhost left intact
* Closing connection #0
The response location,  http://localhost:8080/research-grails-rest/book/show/1, indicates the controller received the request correctly and performed the update.

What am I trying to get at?  One concern I have is support by most/all browsers for the HTTP v1.1 specification.  Another concern is around the heavy handiness around the method support on Grails part.  I concede I am now Grails expert and there may be a very simple solution to this.  I haven't found it yet if there is.  Furthermore, quick check of delete operation from the browser blocks the DELTE method even after altering the allowedMethods.

So what have we learned?  The PUT and DELETE methods have special considerations when involving the Grails built views.  It may be worth approaching another framework to interact with the REST services provided.  However, the controller has tightly integrated the responses on each call with the next view.  I think this is intended due to the nature of Grails application development.

REST - Taking a Closer Look (Part 4)

In the previous posts, we've discussed the general project, defined the concept of REST and taken a look at the list, show and save operations.  Now, let's talk a little shop and dissect the concept of REST a bit further.

REST has some very important design concepts that need to be leveraged to be successful.  First, a rich and easy interface.  This is important for two reasons.  Building a client implementation around a set of REST services can focus on user experience and ignore the data needs.  That is to say, the data is well-defined and the developer building the client can rely on those services to provide specific data.  The application will be built around that data without intermixing the client specific code.

The second important reason is, a developer can build any client around a set of REST services.  Why?  The data has no complicating details blurring the line between the user experience and the data.  In doing so, it makes it more adaptable to move from a purely web-based client to say a mobile web client.  Later, moving to a native client or game console becomes a reality.  Later on down the road, the REST API is published and developers are developing custom applications, much like Twitter, Amazon and others.

Another idea I have read about but do not fully understand is the concept of idempotent resources.  Idempotent is defined as an element multiplied by itself remains unchanged.  The simplest case I can come up with is 1.  1 multiplied by 1 is still 1.

So how does this apply to resource in your system?  Making a request to the same URI should result in the same operation time and time again.  In other words, creating an entry for a book with the same title should result in the same book being created or denied every time.  Only one book is created with that title.  Both PUT and DELETE methods are idempotent.  The GET method is also idempotent given that there are no lasting changes on the resource being requested.  POST is an update operation and can result in attributes of a given resource being altered.  It does not qualify as an idempotent method.

Now, we have defined why REST has good qualities. It provides a rich and easy interface to resources or decouples the client from the data, in doing so, making the data and services scalable.  We have cleared up the concept of idempotent and what that means to a resource in our system.

It is important to remember that REST isn't a specification like SOAP.  It is merely a suggestion of an architectural design around how to serve data.  There are goals within the design to decouple data from the client so that these services are scalable, reliable and well-defined for future client implementations.