5 Signs That Your REST API Isn't RESTful
The author provides five criteria to help you make the distinction between an API that is RESTful based on the original meaning versus the colloquial meaning of REST.
Join the DZone community and get the full member experience.
Join For FreeThere is no doubt that the term REST has undergone significant changes since its inception by Roy Fielding. There was some resistance to this change, most notably from Mr. Fielding in his Untangled Blog. However, all those participating in this resistance have had to acknowledge defeat by now, as the industry has moved past them. We're using the terms REST and REST API not for its original meaning, but, ironically enough, for (basically) opposing SOAP, an arguably more complex and difficult-to-use contender for integration technology.
Nowadays, everything that communicates over HTTP and uses JSON- or XML-formatted messages or the HTTP Methods (get, post, put, delete, etc.) gets called a RESTful API.
This article is not about discussing whether the term is used correctly, whether certain projects are allowed to use the term, or to argue that the currently implemented APIs are somehow defective.
This article is for developers who are wishing to implement a RESTful HTTP interface in its original Fieldingian meaning, thereby solving real integration problems that can be addressed only to a lesser extent with today's colloquial interpretation of the concept.
Because the currently available resources (documentation and software) are ambiguous at best, this article offers a simple list of often seen attributes which can help to keep a design on the right track or to differentiate between the original and new interpretation of REST.
1. Using the Application/JSON Media Type
One of the most often seen attributes of API designs is to use the Media Type application/JSON or sometimes application/XML. With Jersey (JAX-RS), it looks often like this:
@GET
@Produces(MediaType.APPLICATION_JSON)
public List<Product> getProducts() {
...
}
Using generic media types such as JSON is fundamentally not RESTful because REST requires the messages to be self-descriptive. Self-descriptiveness just means that the semantics of the data should travel with the data itself.
The difference is similar to the following two options. See which one you would prefer:
Object getProducts();
Or:
List<Product> getProducts();
The first one just says it returns an Object, in which case you have to know what actual type that object is to be able to cast and use it. The second one explicitly states that it is, in fact, a list of products.
By using generic Media Types, you are relying on the client to know what is inside that JSON message and how to interpret it. This is called implicit knowledge and is primarily responsible for brittleness, the tendency for something to break because of changes made elsewhere.
To counteract brittleness, it is best if all messages define their own Media Type, just as all Types in code define their own Class. This definition should not just include syntax but also how to interpret the message, how to follow its links, how to process its forms if there are any, how to display it on screen, and so on.
2. IDs in Representations
Often, representations returned from the server (or sent to the server) contain IDs (Identifiers) in form of numbers, similar to number typed primary keys in a database table. It looks like this:
{ "products": [
{ "id": 12,
"type": 103,
"name": "ACME Router D12"
},
{ "id": 13,
"type": 145,
"name": "5m UTP Cable"
},
...
]}
Again, taking an example from Java, which API would you prefer?
List<Long> getProducts();
Or:
List<Product> getProducts();
The first one gives you a list of Identifiers with which you can get a real Product from somewhere. The second one returns the explicit Object references that you can use to operate on those Products directly.
Using numerical IDs is not RESTful for two distinct reasons. First, it requires implicit knowledge from the client to know where and how those IDs can be used to get Products. This again increases brittleness and coupling. Second, it doesn't use HTTP's native identifiers (URIs) to identify resources.
The above example should look more like this to be more RESTful:
{ "products": [
{ "id": "/product/12",
"type": "/type/103",
"name": "ACME Router D12"
},
{ "id": "/product/13",
"type": "/product/145",
"name": "5m UTP Cable"
},
...
]}
It is not a big change syntactically but it relieves the client of having to know things implicitly.
3. Documentation Is Concerned With Paths and Parameters
Very often, if any documentation is released about an API, it contains a listing of the paths, parameters, fields that are present in the request or response. Some tools like Swagger or WADL are explicitly centered around these concepts. Both the specification and the documentation generated from these tools look like this:
Path: "/products"
- GET: Get all products
Path: "/product/{id}"
- GET: Get the product with given id
- DELETE: Delete the product
...
See the Swagger Petstore for a complete example of this.
This is not RESTful in the original sense because it assumes that the client has to know all these Paths and Parameters, and what they mean implicitly. However, if the Representations use Links and Forms, like in the previous point, none of this information is relevant to the client, since the client then just follows wherever the Representations lead.
What the Specification and Documentation should do, however, is describe all the Media Types that are defined, much like the API Documentation of Java Code. A very minimal example would look like this:
Type: "application/vnd.acme.productlist+json"
- Represents a paged product listing in the following JSON format:
{ "products": [
{ "self": "/product/123",
"name": "ACME Router"
},
...
],
"nextPage": "/products?page=3",
"previousPage": "/products?page=1"
}
- The "self" link in Products leads to the product listed
- The global "nextPage" link, if present, leads to the next page
of the product listing
- Similarly, the "previousPage" to the previous (if not on first page)
It specifically does not mention where such a representation might be; it simply describes how to deal with it once received. It also doesn't mention how to generate the Path to the next or previous pages or how to append Parameters or Path fragments, it simply provides those links already composed for the client to use. It shouldn't matter how those links are created, and in fact, the server can decide to change such implementation details without notice.
4. URI Templates
URI Templates are URIs with placeholders in them. With the help of named substitution variables, they can be used to generate specific URIs. They look like this:
/product/{id}
/products?page={pageNumber}
/products?startIndex={startIndex}&endIndex={endIndex}
...
These are usually used in specifications or documentations to describe where resources reside and it is expected that clients know these templates and can generate the full URI of a specific resource.
This is done because these resources are not referenced form (linked to) other resources, so the client needs to somehow guess a resource's URI manually. The problem with this approach is the same as before; this makes the clients break easily if some of the rules change or if the server decides to introduce a different resource structure.
The proper solution to these problems is to link those resources from somewhere else and hide all information about the URI structure from the client. Individual products should be linked from a product listing resource. If the product listing resource is paged, then those pages are again linked. The client does not decide to construct the link for the fifth page; rather, it clicks the nextPage links until it arrives at the desired page. Or, if there is a direct link to the fifth page, it chooses that link to go to that page directly.
There are of course cases in which following links is not enough. What if the client wishes to search for a product? It certainly isn't feasible (although it should be possible) to follow links until the desired product is reached. These cases are not that different from simply linking the desired resources, however. The server always needs to tell the client how to construct links to follow. It may actually use URI Templates to do this as long as these are communicated in the messages themselves and not out-of-band (in the documentation, for example). A search page might look like this:
{
"search": "/search?q={query}"
}
The Media Type for this representation has to describe how to interpret the URI Template, how to fill it out, and what the query means so that this knowledge is not implicit anymore. The client then makes the search request based on the information from the search page, not because of some hard-coded rules.
5. Version Number in the URI
A lot of vendors put the version of their API in the URI (for example, Yahoo, Google, Twitter, eBay, and others). This usually looks like:
/api/v1/products
/api/products_v1
/api/products?version=v1
...
From the perspective of the original REST style, these look very suspicious because URIs identify Resources that are supposed to represent some business-relevant concept. These might include Person, Customer, Product, Product Listing, Order, etc. If you ask a business person, "What is a Customer Version 2?" he or she will probably look at you very strangely and wonder whether she will have the opportunity to sell to new, improved customers.
There are practical advantages of URIs that don't change with a version upgrade, like more flexibility when upgrading individual services, being able to bookmark links to resources without them ever changing, etc.
It is, of course, not the Product or Customer concept that is changing, but the Representation, the format of the message, or the features that it supports. There are multiple ways these changes can be described without violating REST. One of the easiest ones is to just version the Media Types themselves:
application/vnd.acme.product-v1+json
Or, the Media Type definition could define extra parameters for the Media Type identification itself:
application/vnd.acme.product+json; version=1
Or, the Media Type could define that the content itself will somehow indicate the exact version, using the XSD identifier, a JSON field, and so on.
There are certainly more ways to do versioning without changing the URI and staying REST conform. Whatever the mechanism, though, it has to be explicitly defined by the Media Type.
Summary
There are at least two meanings of the word REST in use today:
The original meaning in which complex integration problems are solved with rigorous constraints on the architecture.
The colloquial meaning in which services publish some form of (often) JSON-based interface through HTTP.
Neither is better or worse than the other in any objective sense. However, if you explicitly want to leverage the full power of the original concept, you probably face the problem of distinguishing which kind of REST some online documentation, article, or software uses.
Opinions expressed by DZone contributors are their own.
Comments