Please note that this is a little more
technical than my previous articles – sometimes I need to let my inner-geek out.
Simply because RESTful APIs are based on resources and use the HTTP verbs (GET, POST, PUT, DELETE, PATCH), does not mean they should only support CRUD (Create, Read, Update, Delete) operations. RESTful APIs can also be used for performing other actions on resources.
I was challenge with this recently when explaining the concepts of a layered API architecture (see my previous article for more information) during a Domain Driven Design workshop. Core APIs, which expose core domains objects, support pure CRUD operations and make full use of the HTTP verbs. These are well within the perceived CRUD definitions of RESTful services. Process and experience APIs, which orchestrate or compose core APIs to create a defined process, tend to move away from this understanding; and are sometimes a cause for confusion. What HTTP verb should be used for an operation outside of the CRUD set and how should we graft the URL?
Let’s start with the basics. The naming convention for resources in RESTful APIs should be noun based; we work with “accounts”, “customers”, “products”, etc. The basic CRUD operations we perform on these resources are defined by the HTTP verbs. So, for example:
GET http://www.api.com/customers - gets a list of customers
POST http://www.api.com/customers - creates a new customer based on the representation in the body of the request
PUT http://www.api.com/customers/123 - replaces the customer identified by “123” with the representation in the body of the request
PATCH http://www.api.com/customers/123 - updates the customer identified by “123” with the representation in the body of the request
DELETE http://www.api.com/customers/123 - deletes a customer identified by “123”.
The PUT, PATCH and DELETE HTTP verbs imply very specific Update and Delete actions in the realm of HTTP; they will not work for activity-based APIs. A GET request, only consists of the URL to fulfill the HTTP request; you cannot provide content in the request body (we’ll ignore the use of HTTP Headers for now – they serve a completely different purpose). A POST request allows you to provide content within the request body, so is best placed for an activity-based API.
Now that we’ve identified that the HTTP POST verb is the appropriate choice, how then do we graft the URL to identify what activity (“action”) we want to perform on the resource?
A method driven approach to URL design is often used: http://www.api.com/authenticateCustomer or http://www.api.com/validatePaymentRequest. However, while this seems to make sense, in my view, it moves away from the resource orientation of RESTful URLS. You may struggle to consider one resource in isolation, but rather have to be aware of multiple related or interacting resources and actions. This can lead to a plethora of inconsistent URL patterns and approaches – making it difficult for developers to learn how to use your APIs.
Maintaining a resource-based URL representation is surprisingly simple. I use a verb-based terms to identify the action I want to perform on the resource in question. The URL is grafted by appending the verb to the resource-based URL. Using the POST method, I can provide the details required for the activity in the request body.
For example, consider: POST http://www.api.com/customers/123/authenticate - “authenticate” is the action I want to execute on the customer identified by “123”. The request body contains a representation of the customer required for the authentication.
The important principle to be aware of here is that resources MUST be noun-based (describe the resource) and actions MUST be verb-based (describe the action).
By definition and for clarity, REST (Representational State Transfer) is a software architecture style that defines a set of constraints to be used when creating web services. These constraints include:
1. A client-server architecture which supports the separation of concerns principle – allowing components to evolve independently.
2. A stateless client-server communication – where each request from the client contains all the data required to service the request. No client context is stored on the server.
3. Responses must, implicitly or explicitly, define themselves as cacheable or not to prevent clients from getting stale or inappropriate data in response to further requests.
4. A layered system where the client cannot ordinarily tell whether it is connected directly to the end server, or to an intermediary along the way.
5. A uniform interface is fundamental to the design of any RESTful system. It simplifies and decouples the architecture, which enables each part to evolve independently.
Being resource based is inherent in RESTful APIs and the standard set of HTTP verbs tend to imply CRUD operations only; so, I do understand were the misconception comes from.