The one about HTTP Request Methods and the RESTful API

Nobody Nose The Trouble I've Seen - BrittneyBush
Clearly a RESTful dog (photo by BrittneyBush on Flickr)

What HTTP Methods should I use for what API methods? A quesion which, until I began working on a RESTful API, I’d never needed to ask. I’ve been writing an ACL service which required an API. I thought “I don’t know how to write a RESTful API, this is a good opportunity to learn something you reprobate.” so, these are my collected musing on the subject, based on my recent experience.

I started with POSTing to URIs like /v1/adduser and /v1/getuser, which worked OK, it just didn’t feel right. I read through the O’Reilly book and decided I needed to up my game and make some changes.

You see, at first glance PUT and POST seem the same and, for a large part, they are, they RFC says:

The fundamental difference between the POST and PUT requests is reflected in the different meaning of the Request-URI. The URI in a POST request identifies the resource that will handle the enclosed entity. That resource might be a data-accepting process, a gateway to some other protocol, or a separate entity that accepts annotations. In contrast, the URI in a PUT request identifies the entity enclosed with the request — the user agent knows what URI is intended and the server MUST NOT attempt to apply the request to some other resource. If the server desires that the request be applied to a different URI,

Which is a but dull and dry, like beige. Anyway, when writing a RESTful API, you really want to adhere to the proper use of verbs and methods, it all seems a bit airy fairy until you’re given some context and some examples.

__construct()

Let’s say you’re writing an ACL (Access Control Layer) and the ACL needs to have an API which you can use to ask if a user has access to a resource, to add users, resources and roles, perform delete commands and modify stuff. You’ve also decided that the API should be RESTful as it’s a useful way to learn something new.

Your API is going to be located at: http://api.awes.ome/v1/ as it’s good to version APIs, but that’s for another post. For the rest of this article, I’ll be missing out the hostname and just using the URI, because that’s what REST is all about.

REST URI and methods looks like this:

HTTP_METHOD {version}/{resource}/{modifiers}
{body}

Don’t forget, you’ll only have a {body} depending on the HTTP_METHOD you use (GET, for example, doesn’t have a body), speaking of GET…

GET

So, you’ll need to have the concept of “users” (or, in whatever parlance you’d like, “people” or “persons” if you’re a bit PC or even “accounts”) these are a fixed resource. Something that will always be and can be counted as 1 or n. Now we get right down to it, a user is a  “resource”, possibly not in the context of your application, the ACL, but definately in the context of your API, “resource”‘s should have their own URL, like so:

GET /v1/user/mikepearce

What this URL is saying is this: From version one of the api, get me all the data about the user mikepearce. I’m just getting data, it’s read only and the only filter, or where clause of my “get me..” statement is the username. But it is also the resource, doing this:

GET /v1/user

Is pretty useless, what would it return? Not multiple users as it’s not plural. So, the real resource is /user/mikepearce

If you wanted to get multiple users, then “users” is also a resource (not the use of “IS” not “ARE”, you’re not interested in the ACTUAL users, but the concept of all of them or one of them, see? No? Well, you will; keep reading).

GET /v1/users

That will get me all the users, if I want a filter, I can add it on in multiple ways, again, for another post, but you could do it explicitly like this:

GET /v1/users/active/1/gender/male/newsletter/1

or implicitly, like this (your application should know what to do with each URI segment):

GET /v1/users/1/male/1

DELETE

Delete, this one is easy. If you’re deleting a resource (in this case a user) then you’d send this:

DELETE /v1/user/mikepearce
DELETE /v1/users/active/0/ (although, this is a little dangerous).

What is the difference between PUT and POST?

Ah now, here’s the rub! Essentially it boils down to this:

“The client uses PUT when it’s in charge of deciding which new URI the resource should have. The client uses POST when the server is in charge…” – O’Reillys RESTful web services

See? Easy, right. But that doesn’t quite cover everything. Let’s give you some context and then some more context:

PUT

You want to add users to your ACL, who wouldn’t? Afterall an ACL is useless without users, right? Easy and probably finished a long, long time ago. But I digress:

PUT /v1/users/bobmonkhouse

That will add a user called “bobmonkhouse” to your ACL. You’re “PUTting” something somewhere. Imagine that your service is like a shelf and you’ve got a shelf labelled “users” and your arm is the HTTP PUT method and … yeah, perhaps that analogy is a bit thin. Anyway, simply stated, you’re putting a resource at a location.

“Wait!” you cry, “How do I add email addresses and date of births and stuff to the user!?” you sit down in a huff with your arms crossed and eyeball me.

Well, you would still use put, y’see – PUT has a body, rather like POST does. So, if you wanted to PUT extra data along with the resource you’d do this:

PUT /v1/users/tedrogers
email=tedrogers@threetwoone.co.uk&
dob=1935-07-20&
friend=Dusty%20Bin&
password=j0kersw1ld
 
408 Request Timeout by Ape Lad at Flickr
PUT: LIKE A BASKETBALL IN THE FACE .. THE FACE! (image by Ape Lad)

I’ve URL encoded the body of the PUT, but it could be anything, some of you youngsters might even want to use JSON. From here, you can use the URI to create the resource and the body data to populate it.

Updating a resource, for example if a user wants to change their password, or their email address, is as simple as sending the same request as above. You’re PUTting data onto the server, or PUTing document changes to the server. You should, in all instances, send the entire document. So, even if the user was just changing his email address, you should  still send everything you sent with the original PUT to create the resource.

You don’t have to, but it’s the correct way to do things (also, it means you don’t have to check for the existence of all the fields and do if..else wrapped update statements, you can assume that all the fields are there (although that doesn’t mean you shouldn’t validate them!)).

PUT requests to a URI should be idempotent, that is, PUTing the same thing, multiple times should have exactly the same affect as sending it once. If you make the above PUT request three or four times, it won’t create three of four users called tedrogers, it’ll only create one, then, each subsequent PUT updates the resource, whereas a POST will create the user the first time, then, when you make the request again, depending on how you’ve set up your application will either give you an error stating the user exists, or an internal server error, or something entirely different.

POST

Having read the above, you’re possibly wondering, “What would I want to do with POST? I can do everything with I need with PUT”. Well, maybe you can, but probably you can’t.

As I mentioned above, POSTing the same thing multiple times will result in possible multiple copies of your resource, remember, you’re letting the server decide where to put this resource and if it’s something there CAN be multiples of, such as a blog post, comment or message board post, it will create multiples.

Another use for POST is when you’re authenticating a user on you ACL. As well as the ACL informing you of whether a user can access a resource, it’s also got an authenticate method, letting you send a username and password and receiving a response as to whether the user can log in, for example.

In this instance, you’d send a POST:

POST /v1/authenticate
username=jimbowen&
password=bulls3y3

/v1/authenticate/jimbowen isn’t really a resource, it could be, I guess, but just doesn’t feel like a resource. So, you send the username and password as part of the POST body.

“Why can’t I use GET? I’m not actually asking for anything to be saved or stored on the server.” you ask, having read the all the above and taken it in, go you! The problem with using this:

GET /v1/authenticate/username/jimbowen/password/bulls3y3/

Is that the password is now clearly visible in the URI and will be recorded in the server logs. This is NOT a “good thing”, this is a very bad thing. The content of the POST body isn’t recorded anywhere (unless you actually record it) so is ideal for this kind of request.

__destruct()

So, in conclusion, what have we learnt? GET, DELETE and PUT are the three things you need for adding, reading and deleting resources when the client has control over the resource URI and POST is used for when the server decides what to do with the request, whether to create a resource, or to return a value based on criteria you want to remain hidden.

There are, probably, other (better) uses for POST and please leave some extra examples in the comments for others. The above is really just my observations from creating a RESTful API for my ACL.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s