22 ms·
Designing a Pragmatic RESTful API
- _pmf_ 13y agoRESTful: almost correct usage of HTTP verbs to implement something that has nothing to do with REST. But it sure sounds nice.
- ExpiredLink 13y agoThe obligatory "you're doing it wrong" comment following virtually all REST articles.
- johns 13y agoOnce people stop calling it the wrong thing, the discussion can be about something else. 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.
- RyanMcGreal 13y agoIt's why I've come to prefer the term "RESTish". It probably still isn't enough to mollify hard-core purists but indicates that, e.g. the user knows versioning ought to be in the accept header rather than the URL, but also that hardly anyone either creating or using web APIs cares.
- deleted 13y ago[deleted]
- rurounijones 13y agoI have always considered "RESTful" to be analagous to your "RESTish" meaning. 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.
- RyanMcGreal 13y agoThe suffix -ful literally means "as much as will fill", e.g. spoonful, and usually takes the broader meaning "characterized by", e.g. careful. As such, I've always regarded "RESTful" as a full REST implementation, and it seems most other people who have an opinion on the matter do too. 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.
- dragonwriter 13y ago> 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. 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".)
- Kiro 13y ago"A RESTful API should be stateless. This means that request authentication should not depend on cookies or sessions. Instead, each request should come with some sort authentication credentials." 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.
- shaydoc 13y agoYou don't need to do a database look up if you stuff some context into your token and encrypt it with a secret key. When the server receives the request it can simply decrypt the token and deserialize it into some sort of strongly typed usercontext.
- jethroalias97 13y agoAssuming you are using a distributed architecture, there is no way to verify a user without at least one database lookup because the request could be coming into any API server. So in most cases we're not avoiding cookies and sessions just for the sake of it.
- shaydoc 13y agoYou don't need to do a database look up if you stuff some context into your token and encrypt it with a secret key. When the server receives the request it can simply decrypt the token and deserialize it into some sort of strongly typed usercontext
- samsnelling 13y agoJust wanted to say thank you for this. I have been searching for a good article explaining the details of thinking through building an API. This really could not have come at a better time for me! Cheers!
- MostAwesomeDude 13y agoDon't limit yourself to JSON. Your dislike of XML does not mean that JSON is always the right answer. Instead, write code that flexibly can render to any of a set of formats, and use content negotiation to determine which format the user agent wishes to consume. This lets you do things like let the read-only portion of your API be accessible via browser, and it will future-proof you.
- arethuza 13y agoI did think that the criticism of XML for being hard to parse was a bit odd. Although I generally prefer JSON for simpler stuff XML is pretty easy to parse and sift through with XPath.
- _pmf_ 13y agoIt has to do with the awful XML generated by automatic tooling (SOAP by WCF and JEE). 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.
- peterwwillis 13y agoThough for the same dataset, XML will be slower to parse. For performance's sake use JSON.
- arethuza 13y agoI suspect that depends a lot on what platforms are used at the client and server.
- _pmf_ 13y ago> Though for the same dataset, XML will be slower to parse. For performance's sake use JSON. 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.
- peterwwillis 13y agoThis is a well-written and informative article, kudos. 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?
- protonfish 13y agoI think you are confusing the qualities of a good public API and a good internal/private one (for application architecture purposes only.) For internal, I believe REST is the way to go, no contest. Externally is a different story. You would typically only expose a subset of functionality, use different authentication schemes and use a format that can be more easily accessed across domains like JSONP.
- icebraining 13y agoREST only looks complicated because you're seeing it with RPC goggles. In REST, you don't call functions, you just ask for documents and send documents to the server(s). There's nothing particularly complicated in it, it's just a different approach. That said, this article isn't particularly faithful to REST.
- arethuza 13y agoI guess the way I think of REST is that you make requests of different kinds to resources, some of the responses containing documents that contain references to other resources - and all you need to start is the "root" document for the service and an understanding of what the contents of each document mean.
- vyrotek 13y ago
- protonfish 13y agoI am not sure I follow his point about why HATEOAS is not practical, but I know that I have been able to make it work in my own REST APIs using content types. I only return JSON if the Accept header specifies "application/json". (Which is probably what you should be doing anyhow.) I usually also allow an HTML fragment response for the "text/html-fragment" Accept type. The default response type (or if "text/html" is explicitly requested in the Accept header) is the HTML fragment data wrapped in document markup with any forms necessary to expose all functionality in the browser (without JavaScript, but just enough CSS to make it pleasant.) It takes more work, but it not only is the best documentation, you can point the href property of JavaScript click handled hyperlinks right to the REST URIs for proper fallback.
- icebraining 13y agoContent types and HATEOAS are orthogonal properties, I'm not sure how you made the latter work using the former?
- protonfish 13y agoAgreed, I am just trying to guess where the author is confused and reply in a useful manner. I am guessing that too many so-called "REST APIs" return JSON response bodies without explicitly requesting them in the Accept request header. By simply using the Accept header how it is meant to be used, you can return HATEOAS, JSON, XML or whatever format you want specifically designed for the target client.
- icebraining 13y agoWhat does it mean to "return HATEOAS"? HATEOAS is an architectural contrainst, not a format.
- protonfish 13y agoTrue. What I meant was a document that exposes all functionality of the network resource using hypermedia. I did not think that all responses had follow HATEOAS.) Some response should be OK returning partial data or limited functionality as long as something discoverable is explicit and comprehensive.
- vyrotek 13y agoGreat article. I'm actually in the middle of building out a new API. I've built many RESTful APIs but I'm starting to rethink of a couple of things with this new one. Does anyone have any good resources on when it's NOT appropriate to use REST? Or is the assumption that 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. 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?
- dragonwriter 13y ago> Or is the assumption that it should generally work for anything if you model it right? 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.
- ebiester 13y agoI can think of an example: 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.
- walshemj 13y agoWell just as long as you use the right paradime REST is not always the best model to use. 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.
- HNJohnC 13y agoI've been spending many weeks reading articles and books about building a RESTful api. There are a lot of 'ivory tower' guidance articles and books on REST that make little sense in the trenches. That article sums up exactly my own distillation into practical terms of all that information out there. I wish I had read it first.
- icebraining 13y agoLook, REST wasn't something invented in Fielding's study, it was a destillation of an architectural style that was extremely common: Websites. Many ( and at the time, most) are stateless, follow HATEOAS, using only a standardized set of methods, etc. 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.
- joeblau 13y agoGreat article. I wish you would have written this a year ago when I needed this info. I had to learn all of this stuff the hard way. I'm definitely going to use this as a first resource to give to people that I know who are building restful 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.
- oxtopus 13y agoSomething to consider, the author advocates json responses across the board, which is pretty good advice, however, it's incompatible with `204 No Content` responses (also recommended). If you're building a client that connects to an API that could potentially return a `204 No Content` response, you can't assume that there will be json in the body and automatically parse the response.
- delinka 13y agoI don't see the problem here. You get a 204, you don't expect content. If your consumer hits a URL, ignores status codes, and expects content, You're Doing It Wrong. To me, it looks like the HTTP equivalent of a C function that returns NULL.
- oxtopus 13y agoAgreed. Just throwing it out there since I've encountered it before, more than once, where others assume there will always be a response, regardless of status code.
- kailuowang 13y agoRESTful design is still one of the tricky problems I meet on a daily basis. For example, I have blog application in which each blog entry can have multiple versions in its revision history. What should the restful api look like to provide the ability to revert to a certain version?
- beaumartinez 13y agoOff the top of my head—have a BlogPost and a BlogPostVersion resource. BlogPostVersion has all the content, and BlogPost simply has a canonical URL and a link to a BlogPostVersion. You could then PATCH the BlogPost with the link to whatever BlogPostVersion you want to update to. Curious to see what others would recommend.
- kailuowang 13y agoThanks for the reply but maybe I didn't make our requirements clear. The history should be kept intact after the revert - a new version should be created that duplicates the reverted version and become the current version. Thoughts?
- mtrimpe 13y agoIndeed. Creating a new version of your post should be a POST to /posts/X/versions. This would create something like /posts/X/versions/U-U-I-D. 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/ 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.
- kailuowang 13y agoIf I understand your solution correctly, does it mean that it's now the client's obligation to get the content from the revert-to version and create a new version and POST it to /posts/X/versions? That should work, but what if I don't wanna give the client the ability to create version arbitrarily (only allowed to revert to a pre-existing version)?
- l1ghtm4n 13y agoExcellent article. I've just written up REST API design patterns for our group here and it maps very closely to the guidelines you've outlined. Many other posts about REST design are lacking real world experience items like rate limiting.
- buro9 13y agoWe've built a first version of an API that we have in testing at the moment, and it follows a lot of the things laid out in an ebook✝ and in the linked article. 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/ 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 http://pages.apigee.com/web-api-design-ebook.html
- protonfish 13y agoI don't think what the developers are asking for is inherently not RESTful, as long as there is already a strict REST implementation. Adding composite resources in addition to the decoupled ones seems like a intuitive way to improve the usability of the API and the performance of the application (so there aren't so many API calls for common procedures.)
- h2s 13y agoThe 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 URLs http://blog.ploeh.dk/2013/05/01/rest-lesson-learned-avoid-hackable-urls/ http://blog.ploeh.dk/2013/05/01/rest-lesson-learned-avoid-ha...
- memset 13y agoQuestion: in all discussion about API design, the hairiest to me is always authentication. 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?
- buro9 13y agoSSL is not slow. 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.
- T-hawk 13y agoWhile we're dispelling SSL myths, let me add the reminder that SSL does encrypt the URL and querystring and HTTP headers. It doesn't look like it in browsers because they still show the URL cleartext onscreen, but over the wire all of that is indeed inside the encryption envelope. Only the destination IP address isn't encrypted.
- buro9 13y agoAnd whilst we're still here... SNI and SSL. 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.
- obelos 13y agoI prefer providing a "Range" header for pagination. It's typically used for retrieving byte-range chunks of large objects, but it's also applicable to return a subset of a result set, like "Range: records=0-10". This has the drawback of not being easily applied from within a graphical browser, but I don't consider that a big priority for a REST API in the first place. Viva la curl!
- 5avage 13y agoThat's great as long as you're using something with efficient random-access (SQL). If your datastore/back-end is btree-based, however (say, CouchDB for example, or Google search results) you're better off with 'next', 'prev', 'first', etc. pagination. Asking for the 50,000th record means skipping the first 49,999! So, you may be painting your back-end into a corner by counting on random-access being an efficient operation.
- obelos 13y agoThe header's ranges-specifier doesn't specify a syntax, so you can use a docid-based pager just as easily.
- pragueexpat 13y agoWhat about jsonrpc (http://json-rpc.org/ http://json-rpc.org/)? I am using it in a project and I really appreciate the simplicity. Would be curious to hear from others who have experimented with it.
- CodeFoo 13y agoGreat article, I've read many like it, BUT what I can't find is information pertinent to how one should host their API. I submitted an "Ask HN" (https://news.ycombinator.com/item?id=5820761 https://news.ycombinator.com/item?id=5820761) earlier, but could some folks please advise me on the hosting side of "Designing a Pragmatic RESTful API"?
- deleted 13y ago[deleted]
- ajross 13y agoObviously off-topic, but under what circumstances would you ever be returning a field containing a "password" (even a hashed one) over the network in the first place?
- deleted 13y ago[deleted]
- centro 13y agoREST isn't enough. To do it right use the HATEOAS constraint. http://en.wikipedia.org/wiki/HATEOAS http://en.wikipedia.org/wiki/HATEOAS And use application/hal+json http://stateless.co/hal_specification.html 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.
- dragonwriter 13y ago> REST isn't enough. > 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.
- maxisnow 13y agoBefore leaving my current place, our Architect built a PHP micro-framework for our APIs that follows 90% of what's outlined here. I never really understood the magnitude of his work until I tried developing a new API in a different framework. Intelligent routing and query param handling all baked in is so rad.
- legedemon 13y agoOP has mentioned that 'search' is not a noun and hence can't be modeled as a resource. First of all, 'search' can be used as a noun in the sense of quest/query - 'His search for the Holy Grail was fruitful.' Secondly, we happen to have a multi-model search in our application and we treat it as a resource. This has worked out very well for us and our users can easily craft search queries just like for the rest of the RESTful resources.
- bjpirt 13y agoThis is a great article, and although it may raise the ire of some of the REST purists out there, I completely agree with the pragmatic approach. It prompted me to finally publish some of my thoughts on API design that complement the more technical ones in the article: https://news.ycombinator.com/item?id=5831253 https://news.ycombinator.com/item?id=5831253