Just wanted to get feedback on how I am planning to architect my API. Dummy methods below. Here's the structure:
GET http://api.domain.com/1/users/ <-- returns a list of users
POST http://api.domain.com/1/users/add.xml <-- adds user
POST http://api.domain.com/1/users/update.xml <-- updates user
DELETE (or POST?) http://api.domain.com/1/users/delete.xml <-- deletes user
Questions:
- Is it OK to use just GET and POST?
- Is it a good idea that I plan to rely on the filename to indicate what operation to do (e.g. add.xml to add)? Would it be better to do something like this: POST http://api.domain.com/1/users/add/data.xml?
- What's a good way to keep these resources versioned? In my example, I use a /1/ after domain name to indicate version 1. Alternatives would be: http://api1.domain.com... or http://api-1.domain.com... or http://apiv1.domain.com... or http://api-v1.domain.com... or http://api.domain.com/v1/... or
- What's the best way to authenticate?
1) On your design probably not. POST is not idempotent! So you should not use for the update or the delete, instead use PUT and DELETE from Rest
2) A better choice is to use the header Content-Type on the WS call, like: application/xml
3) Also on the header Content-Type u can use it: application-v1.0/xml
4) Not sure if it is the best, but probably the easiest way is to use HTTP's built-in authentication mechanisms in RFC 2617. An example: AWS Authentication
Before you dig into REST, here are some terms you really need to grasp:
Resource - The things/data you want to make available in your API (in your case a "User")
URI - A universally unique ID for a resource. Should mention nothing about the method being performed (e.g. shouldn't contain "add" or "delete"). The structure of your URI however doesn't make your app any more or less RESTful - this is a common misconception.
Uniform Interface - A fixed set of operations you can perform on your resources, in most cases this is HTTP. There are clear definitions for the purpose of each of these HTTP methods.
The most unrestful thing about your URIs as they are right now is that they have information about the operation being performed right in them. URIs are IDs and nothing more!
Let's take a real world example. My name is Nathan. "Nathan" could be considered my ID (or in restful terms URI – for the purpose of this example assume I'm the only "Nathan"). My name/ID doesn't changed based on how you would like to interact with me, e.g. My name wouldn't change to "NathanSayHello" when you wanted to greet me.
It's the same for REST. Your user identified by http://api.domain.com/users/1 doesn't change to http://api.domain.com/users/1/update.xml when you want to update that user. The fact that you want to update that user is implied by the method you're using (e.g. PUT).
Here is my suggestion for your URIs
# Retrieve info about a user
GET http://api.domain.com/user/<id>
# Retrieve set all users
GET http://api.domain.com/users
# Update the user IDed by api.domain.com/user/<id>
PUT http://api.domain.com/user/<id>
# Create a new user. The details (even <id>) are based as the body of the request
POST http://api.domain.com/users
# Delete the user ID'd by api.domain.com/user/<id>
DELETE http://api.domain.com/user/<id>
As for your questions:
Use PUT and DELETE when appropriate and avoid overloading POST to handle these functions as it breaks HTTP's definition of POST. HTTP is your uniform interface. It is your contract with the API user about how they can expect to interact with your service. If you break HTTP, you break this contract.
Remove "add" altogether. Use HTTP's Content-Type header for specifying the mime-type of posted data.
Are you referring to the version of your API or the version of the resource? ETag and other response headers can be used to version the resources.
Many options here. Basic HTTP Auth (easy but insecure), Digest Auth, custom auth like AWS. OAuth is also a possibility. If security is of main importance, I use client side SSL certs.
In REST, the HTTP "verb" is used to denote the operation type: you won't be able to express all the CRUD operations with only "GET" and "POST"
no: the URL of the resource is usually where the "document identifier" should appear
The version of the "document" can be transmitted in an HTTP response header upon creation/modification of the said resource. It should be the duty of the server to uniquely identify the resources - trying to do this on the client side will prove a daunting challenge i.e. keeping consistency.
Of course, there are many variations on the topic...
I did authentication based on headers. Something like
X-Username:happy-hamster
X-Password:notmyactualpassword
If you're concerned about security - do it through SSL.
Other implementations exist, of course. For instance, Amazon with their S3:
http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTAuthentication.html
If you don't have ability to make PUT and DELETE requests, it's considered a good practice to tunnel them through POST. In this case the action is specified in URL. If I recall correctly, RoR does exactly this:
POST http://example.com/foos/2.xml/delete
or
POST http://example.com/foos/3.xml/put
...
<foo>
<bar>newbar</bar>
</foo>
It's a bit offtop, but in regards to versioning and REST overall you might want to take a look at CouchDB. Here is a good book available on-line