Friday, July 17, 2009

REST Method calling

For a few years now, I've been strongly encouraging usage of REST interfaces when building any sort of application. Providing a simple REST interface on top of your application means that you can provide a service and have someone else deal with creating the interfaces. This allows you to have a simple JavaScript client, a Dashboard widget, an iPhone client, and even a Command line client all operating on the same back-end.

The one problem I've found with REST interfaces is that they only allow you to operate on resources with 4 methods, GET, POST, PUT, and DELETE. These methods as stated by most, allow you to Read, Create, Update, and Delete objects ONLY. In working with my applications, I often find the need to let the client perform other operations directly on the object. One possible solution to this problem is to overload the POST method with an optional "ACTION" parameter associated with it. This, however, always seemed hack-ish to me and more of something you'd see in SOAP then REST.

My proposed solution was to use HTTP to it's fullest and allow arbitrary HTTP verbs to be used on objects and collections. For example, if you had a user object at:
/users/moyer
REST says you can do:
GET /users/moyer
To perform a "GET" (which would read the object) operation on the object, or
DELETE /users/moyer
To perform a "DELETE" operation on the object, so why not
RESETPW /users/moyer
To perform a "RESETPW" operation on the object? This turns a simple REST interface into a fully developed remote procedure calling system built directly off of the HTTP specifications.

I have tested this usage using the python httplib standard library, proxying through apache and hitting a CherryPy and Paste backend server. All of my tests suggest that the client libraries and server libraries all will support arbitrary extensions of the HTTP specification. This is the natural flow of progression to extend REST to support more methods on an individual object.

Tuesday, July 7, 2009

OSX WebDav Client

In working on my custom WebDAV server, I discovered an interesting note about the OSX built-in WebDAV client. First of all, if you use finder to copy files (instead of cp in terminal), it sends all files over in chunked transfer-encoding. This is entirely allowed within the WebDAV specification, but it doesn't help that they also send it using the WRONG header. They send the encoding method as "Chunked" instead of "chunked".

While working with Python Paste, I found that chunked encoding wasn't supported at all, so I switched over to using CherryPy. After testing locally and getting everything to work (CherryPy apparently ignores case), I deployed this system to production behind an apache server to add in SSL support (Yes, I plan to use Nginx in the future, but we have apache set up here already). After setting up the proxy, I noticed that I could no longer send files to my WebDAV server and a strange message was appearing in the apache error.log:

[error] proxy: Chunked Transfer-Encoding is not supported
[error] [client xxx.xxx.xxx.xxx] Handler for proxy-server returned invalid result code 22

After a lot of googling, I found a single page (written in german), which describes the issue:

The end result was that I had to enable mod_headers, and place this line in my apache config under the virtual host:

RequestHeader edit Transfer-Encoding Chunked chunked early

This fixes the header before mod_proxy gets to it and changes the "Chunked" to "chunked" which tells apache how to handle the request body.