Insert standard comment about how this does not touch on HATEOS and is therefore not only not REST, but evil and perverse and all that is wrong with the world
Developing REST API per definition of REST cannot be done pragmatically in the way described, so you are going to screw a lot of people if they think this is the last word on REST.
1. REST is a hypermedia API that (somewhat) describes its own services by returning URLs to resources, etc.
Most people don't understand what REST was meant to be that can drive how REST clients were meant to be developed. Some of the major players with "REST" APIs don't either.
2. REST does not have to be versioned if for internal use.
I actually agree with the versioning part, however I've also been on two teams over the past 10 years that developed versioned APIs and neither time did versioning matter, because those APIs were for internal use.
3. This is not a RESTful requirement, but, practically, you shouldn't design an API that allows any querying of resources beyond what should be needed.
This is because of the memory required for caching responses (in a large application), because it therefore can be an easy target for attacks (lets throw a bunch of query params on here... mwhahahahaha), and just because it opens up security holes. Be explicit in what is allowed in your code and your documentation.
4. The querying and filtering I see in this document is insufficient for some applications and interfaces.
It didn't take us long to run into the limitation of the search functionality described in this document in our current REST API based app.
I agree with point three but that could be partially mitigated by throttling, could it not? I recall a good post about making a good API that developers enjoy using and query throttling was a an important point.
This isn't bad and collects a lot of random useful advice in one place but I have a few beefs with it:
repeat akavi's standard comment about HATEOAS here it really does solve some of the problems they're trying to workaround with carefully crafted URLs and versioning. Links are discoverable even if you can't manage to make your URLs clean or even stable.
I think their bit on error codes is all wrong: Using an unfamiliar code number won't throw a human at all, as they come with a self-descriptive label like "Gone" or "Conflict", and should have a body with an explanation of what happened. (Which they recommend) Error messages are for tools, libraries, and proxies; you should use whatever code gets you correct behavior from them (even if it makes no sense), but there's no value in carefully reducing the set of codes you use.
They have some slightly confused ideas about hierarchies, like suggesting version numbers always go at the root. Surely version numbers should be at whatever level the API gets versioned? If you religiously put your versioning at the root, you're going to wind up with the standard API compatibility problem where someone wants to use a v3 feature so they (have to) upgrade all their calls to v3 and then get angry when there's some unrelated compatibility break. Good advice on making it mandatory though.
For God's sake don't allow GET with &method=delete or the like. You can narrow your verbs down to POST and GET but no further.
Insert mention of CSRF here.
The whole architecture section "The API Façade Pattern" is just a bunch of waterfall, API-first design nonsense. Don't invent an API in outer space then try to integrate it with a real system designed separately.
The whole point of decomposing your API into actions on resources is that you don't have to have one unified, consistent, holy API, each resource is an API unto itself that can live on its own and follow its own rules to get something done. If you really love consistency, go whole hog and be consistent with the whole world by using standards, being consistent with just yourself is a form of masturbation.
Totally agree @hakaaak, especially with the care that should be put into making the API navigable using hyperlinks.
It's kind of cool to have a browser-friendly API to play with in the beginning, but it should be pure bonus. APIs are designed to allow a computer program to interact with another one. Favouring query strings over HTTP headers for anything other than altering the projection of a resource is non-sense.
I also don't seem to understand why we must reinvent the wheel and duplicate features when HTTP clearly mentions how to specify an output format, and how to handle partial responses (Range, Content-Range, 206 Partial Response, etc).
PUT is not the equivalent of "update" in CRUD. PUT is meant to replace an existing resource projection with another one. PATCH is the way to go if you want to update specific attributes of an existing resource.
And what about ETags? conditional requests?
It kills me when people mix pragmatism with embracing years of bad practices. That's how we end up with standards where history and legacy are more important than common sense.
>> I also don't seem to understand why we must reinvent the wheel and duplicate features when HTTP clearly mentions how to specify an output format, and how to handle partial responses (Range, Content-Range, 206 Partial Response, etc).
It's not just individual features such as pagination and format handling where the article fails to suggest using standard HTTP features. After the first few pages -which do a pretty good job of explaining the most basic aspects of REST APIs- the document more or less switches to a 'just put it in the querystring'-attitude for about everything that goes beyond basic CRUD operations. Want a subselection of resources based on attribute values? Put the attributes in the query string. Want to limit the returned fields? Put them in the querystring. Need to non-standard logic for handling the request? Signal it in the querystring, so the API user can 'see it'. Want to query something or get a calculated response that needs input parameters (i.e. JSON-RPC)? Put all parameters in the query string. Want to suppress error codes or otherwise instruct the server to change its behaviour? Querystring...
Personally I don't really like using the querystring for every bit of information you want to include in a request, because before you know it the amount of crap you can include in URLS will grow out of hand. I think dumping everything into the querystring pollutes the URI space of your API, which makes it harder to efficiently cache responses or limit access to certain API endpoints.
I'm working on a web application with a REST API at the moment, and I'm trying to avoid using the querystring as much as possible. For example query arguments can also be POST-ed to a query URI that returns a link temporary resource that identifies the query result. Format specification can (and should) be handled using the Accept/Content-Type headers. Pagination can be implemented using the range and partial response headers. Complex queries that are performed often and cannot easily be encoded in a POST body (or a query string) can get their own URI (e.g. '/dogs/by-age/0-1y', '/dogs/by-age/1-5y', etc).
Probably this approach has some serious downsides, but I'm still sticking with it for now. Maybe someone can make me change my mind with good arguments? ;-)
If I had to restart my API over again I would make it self-documentable.
Browsing to /dogs with an Accept: text/html would include a description about that end-point with the possibly accepted parameters, and links to related resources.
If authenticated it would also include the content of that actual route and maybe even a small JavaScript request builder.
I like the idea of self documentation but please don't do this with a text/html header. Oftentimes I want to see in the browser what the GET response is. Probably it's better to explicitly use a .html extension instead.
In the section "What about attribute names?" I think they get it wrong by saying that camel case would be better than snake case because it would make more sense in Javascript that way.
The issue I take with that is you can't assume your API consumer is using Javascript at all. Thus, making it camel case might look right in Javascript or many other languages, but weird in Ruby.
There are a lot of good ideas here, but I think the author messed up on that assumption. A huge portion of modern API usage is in Objective-C, Java, PHP, Ruby, C#. So, attribute naming could be valid as FooBar, fooBar, or foo_bar.
I think the right point would be to be consistent in attribute naming style. Pick one format and use that.
Designing your API to be consumed by one language is mostly foolish unless you are the only one using the API.
Yes, but JSON is JavaScript Object Notation, not (PHP|Ruby|C#|Java|Other) Object Notation. Therefore, since JSON is a serialization of JavaScript, it recommends that you should adopt the JavaScript convention of camelCase.
20 comments
[ 7.4 ms ] story [ 92.8 ms ] threadhttp://martinfowler.com/articles/richardsonMaturityModel.htm...
I don't agree with people who say that only level 3 is "true REST", but there is a qualitative difference.
That is never the implication of that standard comment.
http://martinfowler.com/articles/richardsonMaturityModel.htm...
This gives different levels of "conformance" with the spirit of REST without name calling.
1. REST is a hypermedia API that (somewhat) describes its own services by returning URLs to resources, etc.
Most people don't understand what REST was meant to be that can drive how REST clients were meant to be developed. Some of the major players with "REST" APIs don't either.
2. REST does not have to be versioned if for internal use.
I actually agree with the versioning part, however I've also been on two teams over the past 10 years that developed versioned APIs and neither time did versioning matter, because those APIs were for internal use.
3. This is not a RESTful requirement, but, practically, you shouldn't design an API that allows any querying of resources beyond what should be needed.
This is because of the memory required for caching responses (in a large application), because it therefore can be an easy target for attacks (lets throw a bunch of query params on here... mwhahahahaha), and just because it opens up security holes. Be explicit in what is allowed in your code and your documentation.
4. The querying and filtering I see in this document is insufficient for some applications and interfaces.
It didn't take us long to run into the limitation of the search functionality described in this document in our current REST API based app.
repeat akavi's standard comment about HATEOAS here it really does solve some of the problems they're trying to workaround with carefully crafted URLs and versioning. Links are discoverable even if you can't manage to make your URLs clean or even stable.
I think their bit on error codes is all wrong: Using an unfamiliar code number won't throw a human at all, as they come with a self-descriptive label like "Gone" or "Conflict", and should have a body with an explanation of what happened. (Which they recommend) Error messages are for tools, libraries, and proxies; you should use whatever code gets you correct behavior from them (even if it makes no sense), but there's no value in carefully reducing the set of codes you use.
They have some slightly confused ideas about hierarchies, like suggesting version numbers always go at the root. Surely version numbers should be at whatever level the API gets versioned? If you religiously put your versioning at the root, you're going to wind up with the standard API compatibility problem where someone wants to use a v3 feature so they (have to) upgrade all their calls to v3 and then get angry when there's some unrelated compatibility break. Good advice on making it mandatory though.
For God's sake don't allow GET with &method=delete or the like. You can narrow your verbs down to POST and GET but no further.
Insert mention of CSRF here.
The whole architecture section "The API Façade Pattern" is just a bunch of waterfall, API-first design nonsense. Don't invent an API in outer space then try to integrate it with a real system designed separately.
The whole point of decomposing your API into actions on resources is that you don't have to have one unified, consistent, holy API, each resource is an API unto itself that can live on its own and follow its own rules to get something done. If you really love consistency, go whole hog and be consistent with the whole world by using standards, being consistent with just yourself is a form of masturbation.
It's kind of cool to have a browser-friendly API to play with in the beginning, but it should be pure bonus. APIs are designed to allow a computer program to interact with another one. Favouring query strings over HTTP headers for anything other than altering the projection of a resource is non-sense.
I also don't seem to understand why we must reinvent the wheel and duplicate features when HTTP clearly mentions how to specify an output format, and how to handle partial responses (Range, Content-Range, 206 Partial Response, etc).
PUT is not the equivalent of "update" in CRUD. PUT is meant to replace an existing resource projection with another one. PATCH is the way to go if you want to update specific attributes of an existing resource.
And what about ETags? conditional requests?
It kills me when people mix pragmatism with embracing years of bad practices. That's how we end up with standards where history and legacy are more important than common sense.
It's not just individual features such as pagination and format handling where the article fails to suggest using standard HTTP features. After the first few pages -which do a pretty good job of explaining the most basic aspects of REST APIs- the document more or less switches to a 'just put it in the querystring'-attitude for about everything that goes beyond basic CRUD operations. Want a subselection of resources based on attribute values? Put the attributes in the query string. Want to limit the returned fields? Put them in the querystring. Need to non-standard logic for handling the request? Signal it in the querystring, so the API user can 'see it'. Want to query something or get a calculated response that needs input parameters (i.e. JSON-RPC)? Put all parameters in the query string. Want to suppress error codes or otherwise instruct the server to change its behaviour? Querystring...
Personally I don't really like using the querystring for every bit of information you want to include in a request, because before you know it the amount of crap you can include in URLS will grow out of hand. I think dumping everything into the querystring pollutes the URI space of your API, which makes it harder to efficiently cache responses or limit access to certain API endpoints.
I'm working on a web application with a REST API at the moment, and I'm trying to avoid using the querystring as much as possible. For example query arguments can also be POST-ed to a query URI that returns a link temporary resource that identifies the query result. Format specification can (and should) be handled using the Accept/Content-Type headers. Pagination can be implemented using the range and partial response headers. Complex queries that are performed often and cannot easily be encoded in a POST body (or a query string) can get their own URI (e.g. '/dogs/by-age/0-1y', '/dogs/by-age/1-5y', etc).
Probably this approach has some serious downsides, but I'm still sticking with it for now. Maybe someone can make me change my mind with good arguments? ;-)
I'm one of the authors of http://greendizer.com/docs/api/, and https://github.com/mohamedattahri/Nuages
Take a look at them.
Browsing to /dogs with an Accept: text/html would include a description about that end-point with the possibly accepted parameters, and links to related resources.
If authenticated it would also include the content of that actual route and maybe even a small JavaScript request builder.
The issue I take with that is you can't assume your API consumer is using Javascript at all. Thus, making it camel case might look right in Javascript or many other languages, but weird in Ruby.
There are a lot of good ideas here, but I think the author messed up on that assumption. A huge portion of modern API usage is in Objective-C, Java, PHP, Ruby, C#. So, attribute naming could be valid as FooBar, fooBar, or foo_bar.
I think the right point would be to be consistent in attribute naming style. Pick one format and use that.
Designing your API to be consumed by one language is mostly foolish unless you are the only one using the API.