Designing a Pragmatic RESTful API
vinaysahni.com
vinaysahni.com
The epiphany we had was that whilst machines do access the API, the developer is always the customer and user. Everything we do should help the developer, and if we have to break rules to help them... then largely we should.
I've built a couple of very pure REST APIs in the past, but had a lot of developers pushing back and demanding something simpler. To not use media types so precisely, to be more accepting of what data is sent, to provide meta-data along with the resource (most seem to prefer an envelope), to prefer composite resources over very decoupled interfaces, etc.
This time, I haven't even tried to build a pure REST API. This time I've just mixed together the bits that developers I've spoken to liked and prefer. Adjusting as I went depending on how it was received.
http://microcosm-cc.github.io/
That's the docs for it, and we get the arguments out the way right at the beginning. All we're trying to do is build an API that helps developers get their task done. We're not done, and I know it's not pure anything... but the feedback we're getting is far more positive than any pure REST API I've ever built.
✝ If you are willing to give out a fake email address then this free eBook is a great resource and has a lot of sane information presented clearly: http://pages.apigee.com/web-api-design-ebook.html
The epiphany we had was that whilst machines do access
the API, the developer is always the customer and user.
Everything we do should help the developer, and if we
have to break rules to help them... then largely we
should.
Thank you, this articulates my disagreement with the idea of hashing all URLs so that client developers are forced to follow links returned by the API instead of generating their own URLshttp://blog.ploeh.dk/2013/05/01/rest-lesson-learned-avoid-ha...
Hyperlinking has a few benefits, the biggest being discoverability without the need for browsing some documentation that explains how to build URLs, but it's not always the best possible solution for every application -- and it typically leads to chatty applications.
The only thing that bothers me, though, is when these RPC APIs are called "RESTful" just because they use HTTP verbs correctly.
Why work halfway towards A, when we could define a more realistic B and implement it fully? We spend too much time justifying which parts of the holy book to ignore.
There are lots of private APIs that operate this way; for example, much of Comcast's internal stuff is pure, hypermedia driven REST. But it's not open source, so you don't hear about it.
A YC-funded company, Balanced Payments, does an excellent job as well.
> those seem too fundamentally different from any API I might create.
Right! That's because you're primarily thinking of RPC styles, so of course it will seem foreign. Try this sentence on for size, from a different time period:
"But who has truly object oriented objectives in mind? Some people tell me that Smalltalk or C++ are examples, but those seem too fundamentally different from any code I might write."
That's not to say RPC is a bad thing: often times, it's just fine. But if you have the problems REST is designed to solve, REST will solve them much better.
My own criteria is that RESTful interfaces should be easy to use from the command line using curl (or any other similar tool) - not that this is the main way an interface will be used, but it helps a lot with exploration and troubleshooting.
That said, it reminds me how fucking overcomplicated REST HTTP API is for 99% of uses. As an API user, all I want is to call a function on a server, pass it some arguments and get a result. I want it to be dead simple, and REST is probably the opposite of that.
Finally, it also occurs to me that most API calls may call one function which returns lots of data that I don't need. Specifying the data types and field names I want in the query would simplify parsing and potentially reduce bandwidth use (if you've ever seen an API call that returns a user's profile when all you wanted was their last login timestamp, you know what I mean). edit Whoops, didn't see he mentioned the field limiter... why don't more people do that?
That said, this article isn't particularly faithful to REST.
I'm currently working on a few large B2B APIs and it's been difficult to implement REST. The value of these APIs come from the actual work performed and not just updating the state of a few rows in a DB. I have very "business logic" heavy endpoints which take many parameters and return very different payloads. As much as I hate it, sometimes business and practicality comes before purity. :)
I actually asked for some feedback in a comment below buried somewhere: https://news.ycombinator.com/item?id=5819821
Just don't make an RPC API and call it RESTful ;)
Almost all web APIs out there aren't REST APIs because they don't respect the "driven by hypermedia" constraint which makes sense because this constraint was put in place for human users driving applications through web browsers, not for machines.
I've started to formalize a new "Web API" architecture style that takes the best of REST but leaves the requirements and constraints that don't make sense. See this blog post: http://blog.restlet.com/2013/05/02/how-much-rest-should-your...
Furthermore, if you really wanted to, HTTP does allow new verbs to be added, so...
In my mind I think of some things e.g.: google search, as a function not a resource. Trying to think about what the resource might be seems tangential to what I am trying to do.
If you want a performance advantage you must parse the limit-params and select only the needed fields from db and send them to client. But this make the backend complicated.
If something is misspelled (frontend/backend) you need more time to find the error.
It is easier and cleaner provide some additional calls for specific data (like lastLogin).
If you use something like Backbone in frontend, you are happy to access all needed data so easy, why restrict them?
Ok if you have an heavy used performance critic application, you can start optimizing. But why, welcome to the cloud, add some processes ;-)
How is this not dead simple in REST? Can you provide a specific example and how REST makes it complicated? Because I don't see it.
I also hate this nitpicking, but it's clearly not going away so you're better off not inviting it by using the term incorrectly.
If I am 100% REST then I would say "I have a REST API". If, like most companies, I am not following all the REST conventions then I would say "RESTful" api.
The moaning about "RESTful has been hijacked by people who don't know REST" by the REST purists always struck me as strange when they could have made that simple distinction.
I borrowed RESTish from Dan Savage's concept of "monogamish", meaning a relationship that conforms generally but not rigidly and precisely to the norms of monogamy. As such, a RESTish API conforms generally but not rigidly and precisely to the norms of REST.
If you aren't following REST conventions, its probably better to say "HTTP API" and not make any claims at all related to REST (except, perhaps, negative ones like "non-REST".)
The article recommends SSL, but the internet says that "SSL is slow." Is there a guide to using SSL correctly, and techniques for making this more efficient? An SSL primer?
It also recommends using oauth. There are hundreds of libraries for consuming oauth APIs. What exists (I'm a Python+Flask guy, but really any help would be great) for implementing oauth authentication for my own API?
Grab the latest version of Nginx, turn on SPDY, enable SSL session cache.
You must always serve your API over SSL, as auth information is going to be in headers or the querystring and both would be readable by a MITM if you do not use SSL.
Nginx 1.4 statements to pay attention to (sample config):
ssl on;
ssl_certificate /etc/ssl/domain.crt;
ssl_certificate_key /etc/ssl/domain.key;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_ciphers RC4:HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_stapling on;
spdy_headers_comp 1;
If you're not using Nginx, why not? Just use it as a reverse proxy and drop it in front of whatever you are using.Thanks to Internet Explorer, and the early versions of the stock browser on Android, you will need a unique IPv4 address for your SSL endpoint.
You cannot safely serve multiple SSL sites on the same IP.✝
Basically: The hostname is also encrypted, so the SSL requests on some browsers require a unique IPv4 address. Your provider will give you one if you say the magic word "SSL" to them.
✝There are ways for most browsers, but not for IE and early Android browsers. Thankfully mobile device churn will cure us of the Android issue, but the affected IE versions will take longer to die.
As a result, SSL really has nothing to do with HTTP and could be used to wrap other protocols. Check out stunnel ( https://www.stunnel.org/index.html ) which can be used to arbitrarily encrypt communications for any TCP based protocol
It's a strict layering: TCP - SSL ("Secure Socket Layer", right?) - HTTP
There are two (and a half) ways of using a SSL certificate for multiple hostnames on the same IP address / interface: SNI (Server Name Identification (?)) and Subject Alt Names or Wildcard certificates. SNI extends the SSL protocol to send the hostname during the client handshake. The Subject Alt Name extension, which has been more reliable and available for me, adds multiple hostnames to the certificate for the client to match against. Wildcards do the same thing, patternistically: *.example.com.
That said, we're on our way to a bright SNI filled future, we just have to get over the hump of old versions of Windows and some old mobile devices before it's common enough to be used reliably.
To me, it looks like the HTTP equivalent of a C function that returns NULL.
That article sums up exactly my own distillation into practical terms of all that information out there. I wish I had read it first.
There's nothing difficult or impractical about REST, and the proof is that we use it every day.
Now, it's not aplicable to every case, of course. In those cases, just use something else, and don't call it REST.
They aren't orthogonal. Content-types are central to HATEOAS:
From one of the key descriptions [1] of the HATEOAS constraint on REST:
A REST API should spend almost all of its descriptive effort in defining the media type(s) used for representing resources and driving application state, or in defining extended relation names and/or hypertext-enabled mark-up for existing standard media types. Any effort spent describing what methods to use on what URIs of interest should be entirely defined within the scope of the processing rules for a media type (and, in most cases, already defined by existing media types). [Failure here implies that out-of-band information is driving interaction instead of hypertext.]
[1] http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hyperte...
If you are doing a REST architecture with a protocol other than HTTP, sure.
But since the Content-Type header is the mechanism by which HTTP communicates media types, and since in-band, rather than out-of-band, communication of resource locations and media types is essential to HATEOAS, the Content-Type header is a pretty important mechanism in HATEOAS when using HTTP.
file document
document: HTML document, UTF-8 Unicode text
You can distinguish between media types without using the Content-Type header or out-of-band communication. In fact, there's a (non-standard) header for preventing some browsers from replacing the Content-Type value with their own guess.It's obviously useful, especially for distinguishing between similar media types (e.g. JSON document with different schemas), but not necessary for HATEOAS.
Quoting from wikipedia: "A REST client enters a REST application through a simple fixed URL. All future actions the client may take are discovered within resource representations returned from the server."
Does the JSON representation of a Employee object returned URLs as a part of the body for the resource addresses for any "child" objects?
I don't think it can be considered HATEOAS if the answer to either is no.
If the answer to those questions is no (whether the format of the response is JSON or anything else), then you aren't using hypermedia as the engine of application state.
Why, no, it doesn't, because it takes 3 parameters, each of which can take 10,000 possible values, and I don't want to transmit a trillion options every time someone pings the root.
I mean, I considered documenting how to pass the parameters on a client's first entry but the HATEOAS crowd told me I was just re-creating RPC, and I agreed. So no HATEOAS.
You could then PATCH the BlogPost with the link to whatever BlogPostVersion you want to update to.
Curious to see what others would recommend.
Since REST is all about mapping to the underlying semantics of HTTP you'd then want to make /posts/X redirect to /posts/X/versions/U-U-I-D
Since there's nothing wrong with updating your resource under the hood (think of e.g. http://www.weather.com/weather/right-now/) posts/X would simply always redirect to the latest version.
If you don't always use the latest version by definition, then you'd probably do a PATCH with the new version id to /posts/X, or a PATCH with 'active: true' to /posts/X/version/O-L-D.
PATCH /posts/X
{ "version": "older-revision" }
or PATCH /posts/X/versions/older-revision
{ "active": true }
Access control is completely orthogonal to this; so for your sample case you would just return a 403 for any other calls (like e.g. POSTs to /posts/X/versions)Seriously REST isn't a mystery. I think the problem is few understand what it is. Here is my 30-second version:
1. Identification of resources and manipulation through representations. This means a network resource should have a URL that is the same no matter what you are doing to it - getting changing, removing, modifying or any custom manipulation. For the Web, use HTTP verbs and request body data to define the actions.
2. Self-descriptive error messages. Don't return 200 OK for everything. Use status codes and verbose response bodies to describe what happened.
3. Hypermedia as the engine of application state. Expose ALL functionality in HTML using hyperlinks and forms.
However I think what this whole discussing is missing is the properties that you derive by adhering to a REST design.
I think there should be some tests of a design to see if you are actually getting the benefits of REST.
For example in a REST design you can re-arrange the internal URL's in a server and the site is still usable to clients because they are following links from the root.
Why do we want this ability to rearrange URLs?
Example: think of posts here on HN. One thing a specific media format would include is a "reply" link, but on hellbanned posts that link would absent, so that state would be inaccessible to clients.
Or say you've used comments on your blog, so each post has a link to the list of comments about it. Now you switch to Disqus, and so you could change the URL to point to their comments pages instead, and a decent client would use it transparently (assuming good media types).
All of this is taken for granted and used a lot on the real RESTful space: the HTML Web.
One way is to use the newest version in Client and the Server has to convert old Data to new Data, then deliver to Client. But sometimes it not so easy, depend on complexity of your data.
Other way: convert all Data to new Version and change Data-Access in the old Api Version (but here is the Problem with: never change a running system, things that work before could go wrong). And if you have a huge site with many users, it is not possibly to interrupt the service.
To maintain many versions is for a short period ok, but for longer usage not practicable.
Did somebody have experience with that ?
I ask this because the API I'm building is for a B2B product and lot of the "actions" are not state change requests. In fact, they are a lot of verbs which fire off lots of business logic and don't really map well to a single entity. Some endpoints also need to return very large and deeply filled entities in a single call.
I've started to investigate JSON-RPC, is that a good option?
It should generally work for anything if you model it right.
> I ask this because the API I'm building is for a B2B product and lot of the "actions" are not state change requests.
How can anything both be an action and not be a state change request?
> In fact, they are a lot of verbs which fire off lots of business logic and don't really map well to a single entity.
A "verb that firest off lots of business logic" sounds like a RPC-style metaphor.
In a REST architecture -- and they don't necessarily map perfectly so with more description I might characterize this differently -- I'd characterize that as most likely a entity creation (HTTP POST) action (the entity being a particular invocation of the underlying logic, and containing all the necessary parameters.)
> Some endpoints also need to return very large and deeply filled entities in a single call.
How does this conflict with REST. REST has nothing against "large and deeply filled entities". (Remember that HTTP is itself a RESTful API, and obviously is designed for a use case where "large and deeply-filled entities" are frequently returned.)
You may want to define specific media types for each of these types of entities to do REST properly, but since in practice you are going to have to define the structure of the entity returned no matter what application architectural style you are using, this isn't really a substantial extra workload for REST.
Send a message to the server to process all approved cases, which has no connection to an individual resource. The client has no fundamental knowledge of all server-side resources that may or may not be affected, and may not even be allowed that information.
It's an action, but it's not really a post. You're not creating a new resource. You're not patching anything, you're not really getting anything... It's closest to a PUT, but you're not really updating a particular resource...
This may not be a document-based API like REST expects, but it is a fairly common enterprise requirement for a system.
"Individual resources" are defined by the needs of the API. If you need an endpoint that can be given a command to process all approved cases, then that is an "individual resource".
The particular kind of resource I'd normally model it as is one which is or has a collection resource in which individual command instances are the members of the collection.
> It's an action, but it's not really a post.
I disagree. Submitting a new request to initiate the action is exactly a request to create a new command resource subordinate to the collection of commands subordinate to the command processing endpoint resource, which naturally maps to an HTTP POST action to the collection. The processing of approved cases, and the resulting changes to the backend data store, are consequences (side effects) of the creation of that resource.
> This may not be a document-based API like REST expects
REST doesn't expect a "document-based API". It expects a resource based API. Commands, collections of commands, and endpoints which have collections of commands as well as other subordinate resources are all, themselves, valid resources, whether or not they are sensibly described as "documents".
Ah, well said. It's so hard to find good examples of this though. Most REST tutorials focus on simple nouns that happen to map nicely to tables. But you're suggesting that "resources" could be far more abstract. But, if I were to treat Commands as resource and perhaps make it my only resource, isn't that essentially RPC?
If you have a root URL for the API, and all the endpoints are located via links from the document at the root URL, and submitting commands gives back a results resource that either is or provides a URL for the output, and all the different resources have media types that define what is needed to understand/process them without requiring out-of-band information beyond that describing the media types and the root URL of the API, then it can still be REST.
I think its probably fairly common that there are situations where the "active" side of a REST API will largely look that way, even if there is a read-only component that looks like of the collection-resources-as-tables, individual-resources-as-table-rows business data view.
That being said, its probably not really good REST if things being modelled as abstract commands with side effect of changes on multiple entities really could be modeled as changes to some particular business entity that also had side effects on other business entities. But whether that applies to the commands you are using will depend on your use case.
No, this is not true. Each constraint of REST comes with drawbacks, and if you can't afford those drawbacks, you can't do it RESTfully. Fielding's thesis is very upfront about this.
The biggie: latency. If you need sub-10ms responses, REST is the wrong way to go about modelling your problem domain.
The second: client-server. If you want the server to initiate behavior on the client, REST is the wrong way to go. See the wealth of WebSockets/Meteor/Real Time Web (tm) frameworks and their hype for examples of when you'd want to do this.
That being said, I'm not convinced that your particular objections, aside from responding to "anything" in a different sense than intended in context, are really accurate.
> The biggie: latency. If you need sub-10ms responses, REST is the wrong way to go about modelling your problem domain.
HTTP might be problematic here, but I don't see why REST is problematic. (REST doesn't rely on HTTP -- in fact, HTTP is itself a REST-based system -- and can be implemented over protocols with different performance characteristics.)
Its obviously a problem for every request to navigate from the API root if you have tight latency constraints, but there is nothing unRESTful about having a client cache the locations of the key resources it is interested in after the first access. In fact, reducing latency by encouraging cacheability is an explicitly-cited motivation for REST.
> The second: client-server. If you want the server to initiate behavior on the client, REST is the wrong way to go.
If you want system A to initiate a behavior on system B, then in the context of REST with regard to the behavior at issue, A is a client consuming an API and B is a server providing an API. If it is necessary for other reasons for A to be an HTTP server and B to the HTTP client, then you obviously aren't going to be doing typical REST-over-HTTP to implement the API that A is consuming and B is providing. But there is no reason that you can't use a REST architecture for the API. (OTOH, since, in simple cases, the API implementation will likely be being provided as Code-on-Demand to B by A, there's may not be a lot of reason to use REST, but it could help reduce coupling between different components on A.)
Gotcha. You're right that I got this wrong, but I think my objection still stands; a peer-to-peer interaction model is still not RESTful.
> Its obviously a problem for every request to navigate from the API root if you have tight latency constraints,
Even in truly RESTful systems, 'every request' wouldn't navigate from the root; the first interaction starts there, but it's not like you keep going back to the root every single time you want to do anything.
> In fact, reducing latency by encouraging cacheability is an explicitly-cited motivation for REST.
Absolutely. I was thinking of the 'layered system' constraint. From http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch... :
> The primary disadvantage of layered systems is that they add overhead and latency to the processing of data, reducing user-perceived performance.
You are right that caching helps balance this out, but not everything can be cached; for example, a first-person shooter game would be hard to cache.
> A is a client consuming an API and B is a server providing an API.
Even if it's 'oh they're just two different APIs working together', it's not a singular API, which is what we're talking about here.
> Even if it's 'oh they're just two different APIs working together', it's not a singular API, which is what we're talking about here.
I thought we were talking about the utility of REST architecture for the API(s) involved. Obviously, if you have requirements which require two different APIs where the consumers of one API are the providers of the other API, then regardless of architecture, it won't be one API, but that's orthogonal to the architecture appropriate to either or both APIs.
I'm slightly a bigger proponent of HATEOAS, but if you don't need it yet, I think you can always add it in later. I've been the giver and receiver of bad things when it's not followed, but that is generally around massive projects.
Doesn't that mean you need to do a database lookup to verify the user with every request? Seems like a lot of overhead just for the sake of avoiding sessions.
When the server receives the request it can simply decrypt the token and deserialize it into some sort of strongly typed usercontext.
AFAIK, neither signatures or "something you have, know" alone fixes replay attacks. Since this is a well known problem in cryptography, many solutions exists. All of which are probably overkill for this use.
Alternatively, if a time limited token is practical, use a self-signed expiring token.
One reason to avoid sessions is security aspect of it. Cookies are handled automatically by the browser which opens the API up to XSS
Whether or not that is a lot of overhead depends also on how much work you were going to do to process the rest of the request. If your API allows sorting and filtering of a large data set, like the article suggests, then the authentication overhead is probably relatively small.
The API user first gets a token using credentials. Future requests use the token for authentication.
A new token will be required periodically.
Is it because the authentication part is a lot of work for the server or client?
Is it for the negligible (in this context) security benefits of not using the same secret-key for all traffic?
To do it right use the HATEOAS constraint. http://en.wikipedia.org/wiki/HATEOAS
And use application/hal+json http://stateless.co/hal_specification.html
The more we follow these simple constraints the more we can start to build tooling to consume any API without having to know much about it ahead of time.
That said, well written article.
> To do it right use the HATEOAS constraint.
The HATEOAS constraint is part of REST; if you aren't using it, you aren't doing REST.
I built a tool to use a third partys restful api for a when they should have built it using message queuing as that suited the application.
Hand-generated XML can be just as nice as using hand-generated JSON, and on the other hand automatic domain-model-to-JSON mapping can be as ugly as any XML monstrosity.
Loading a huge JSON file is almost certainly slower than using a SAX parser for a huge XML file. Maybe there are SAX like approaches for JSON, too.
Creating idiomatic XML, on the other hand, is a little more tricky. Should something be a tag or an attribute? What should it be named?
To businesses that need to support multiple formats (enterprise requirements?), XML + XSLT sounds like a fair approach - it allows you to simultaneously create idiomatic XML & JSON
By separating out the rendering-to-an-output format from the basic logic of the application, you get similar benefits without creating a dependency on XML handling libraries and requiring another implementation language (XSLT) for the rendering component.