Pekka 웃 Pekka 웃 - 4 months ago 20
reST (reStructuredText) Question

Understanding REST: Verbs, error codes, and authentication

I am looking for a way to wrap APIs around default functions in my PHP-based web applications, databases and CMSs.

I have looked around and found several "skeleton" frameworks. In addition to the answers in my question, there is Tonic, a REST framework I like because it is very lightweight.

I like REST the best for its simplicity, and would like to create an API architecture based on it. I'm trying to get my head around the basic principles and have not fully understood it yet. Therefore, a number of questions.

1. Am I understanding it right?

Say I have a resource "users". I could set up a number of URIs like so:

/api/users when called with GET, lists users
/api/users when called with POST, creates user record
/api/users/1 when called with GET, shows user record
when called with PUT, updates user record
when called with DELETE, deletes user record


is this a correct representation of a RESTful architecture so far?

2. I need more verbs

Create, Update and Delete may be enough in theory, but in practice I will have the need for a lot more verbs. I realize these are things that could be embedded in an update request, but they are specific actions that can have specific return codes and I wouldn't want to throw them all into one action.

Some that come to mind in the user example are:

activate_login
deactivate_login
change_password
add_credit


how would I express actions such as those in a RESTful URL architecture?

My instinct would be to do a GET call to a URL like

/api/users/1/activate_login


and expect a status code back.

That deviates from the idea of using HTTP verbs, though. What do you think?

3. How to return error messages and codes

A great part of REST's beauty stems from its use of standard HTTP methods. On an error, I emit a header with a 3xx,4xx or 5xx error status code. For a detailed error description, I can use the body (right?). So far so good. But what would be the way to transmit a proprietary error code that is more detailed in describing what went wrong (e.g. "failed to connect to database", or "database login wrong")? If I put it into the body along with the message, I have to parse it out afterwards. Is there a standard header for this kind of thing?

4. How to do authentication


  • What would a API key based authentication following REST principles look like?

  • Are there strong points against using sessions when authenticating a REST client, other than that it's a blatant violation of the REST principle? :) (only half kidding here, session based authentication would play well with my existing infrastructure.)


Answer

I noticed this question a couple of days late, but I feel that I can add some insight. I hope this can be helpful towards your RESTful venture.


Point 1: Am I understanding it right?

You understood right. That is a correct representation of a RESTful architecture. You may find the following matrix from Wikipedia very helpful in defining your nouns and verbs:


When dealing with a Collection URI like: http://example.com/resources/

  • GET: List the members of the collection, complete with their member URIs for further navigation. For example, list all the cars for sale.

  • PUT: Meaning defined as "replace the entire collection with another collection".

  • POST: Create a new entry in the collection where the ID is assigned automatically by the collection. The ID created is usually included as part of the data returned by this operation.

  • DELETE: Meaning defined as "delete the entire collection".


When dealing with a Member URI like: http://example.com/resources/7HOU57Y

  • GET: Retrieve a representation of the addressed member of the collection expressed in an appropriate MIME type.

  • PUT: Update the addressed member of the collection or create it with the specified ID.

  • POST: Treats the addressed member as a collection in its own right and creates a new subordinate of it.

  • DELETE: Delete the addressed member of the collection.


Point 2: I need more verbs

In general, when you think you need more verbs, it may actually mean that your resources need to be re-identified. Remember that in REST you are always acting on a resource, or on a collection of resources. What you choose as the resource is quite important for your API definition.

Activate/Deactivate Login: If you are creating a new session, then you may want to consider "the session" as the resource. To create a new session, use POST to http://example.com/sessions/ with the credentials in the body. To expire it use PUT or a DELETE (maybe depending on whether you intend to keep a session history) to http://example.com/sessions/SESSION_ID.

Change Password: This time the resource is "the user". You would need a PUT to http://example.com/users/USER_ID with the old and new passwords in the body. You are acting on "the user" resource, and a change password is simply an update request. It's quite similar to the UPDATE statement in a relational database.

My instinct would be to do a GET call to a URL like /api/users/1/activate_login

This goes against a very core REST principle: The correct usage of HTTP verbs. Any GET request should never leave any side effect.

For example, a GET request should never create a session on the database, return a cookie with a new Session ID, or leave any residue on the server. The GET verb is like the SELECT statement in a database engine. Remember that the response to any request with the GET verb should be cache-able when requested with the same parameters, just like when you request a static web page.


Point 3: How to return error messages and codes

Consider the 4xx or 5xx HTTP status codes as error categories. You can elaborate the error in the body.

Failed to Connect to Database: / Incorrect Database Login: In general you should use a 500 error for these types of errors. This is a server-side error. The client did nothing wrong. 500 errors are normally considered "retryable". i.e. the client can retry the same exact request, and expect it to succeed once the server's troubles are resolved. Specify the details in the body, so that the client will be able to provide some context to us humans.

The other category of errors would be the 4xx family, which in general indicate that the client did something wrong. In particular, this category of errors normally indicate to the client that there is no need to retry the request as it is, because it will continue to fail permanently. i.e. the client needs to change something before retrying this request. For example, "Resource not found" (HTTP 404) or "Malformed Request" (HTTP 400) errors would fall in this category.


Point 4: How to do authentication

As pointed out in point 1, instead of authenticating a user, you may want to think about creating a session. You will be returned a new "Session ID", along with the appropriate HTTP status code (200: Access Granted or 403: Access Denied).

You will then be asking your RESTful server: "Can you GET me the resource for this Session ID?".

There is no authenticated mode - REST is stateless: You create a session, you ask the server to give you resources using this Session ID as a parameter, and on logout you drop or expire the session.