7 ms·
Designing a RESTful API That Doesn't Suck
- gbog 14y agoI wonder if there is some convention for automatic api exploration. Would be nice also for auto documentation.
- lucaspiller 14y agohttp://en.wikipedia.org/wiki/Web_Services_Description_Language http://en.wikipedia.org/wiki/Web_Services_Description_Langua... ?
- untothebreach 14y agoWSDLs appear to be permanently associated with SOAP, so I don't see them gaining much traction with the REST crowd.
- hunvreus 14y agoThere are ways to do that, I usually find them cumbersome. There are also ways to "easily" maintain API references (Swagger, I/O Docs). I posted something about why we don't use these tools not too long ago: http://devo.ps/blog/2013/02/07/why-we-dropped-iodocs-and-swagger.html http://devo.ps/blog/2013/02/07/why-we-dropped-iodocs-and-swa...
- gamache 14y agoThere is -- hypermedia. That's the practice of driving your API by following hyperlinks, rather than by constructing URLs and requesting them. There are several schemes of encoding link information in API resources. I like the Hypertext Application Language, or HAL, the best. Check it out: http://stateless.co/hal_specification.html http://stateless.co/hal_specification.html
- byroot 14y agoThe Github API started to implement it but is now going backwards[0]: Standardize on existing *_url attributes for hypermedia. Remove all _links objects If somebody knows the rational behind it I would love to hear it. [0] http://developer.github.com/ http://developer.github.com/
- stuffihavemade 14y agoHow about the most important concept, http://en.wikipedia.org/wiki/HATEOAS http://en.wikipedia.org/wiki/HATEOAS ?
- hunvreus 14y agoI was planning on diving in deeper in my next post. This was more of a quick and practical list of things you should follow for your API not to suck too much. But yeah, I agree.
- shintoist 14y agoWould love a practical HATEOAS point by point write up like the posted article. Nicely written
- erjjones 14y ago+1 for HATEOAS links . this will drive a semantic web for tomorrow
- yuchi 14y agoI still don't get why we're using the API version in the url. We should use the specialized content-type instead!
- arethuza 14y agoYou could argue that versions of the API are themselves resources and should be discoverable - the Salesforce REST API does this and while I actually prefer the specialized content-type approach myself it certainly does work.
- Kabacaru 14y agoBecause it's harder to set the content-type from browsers. Perhaps if your API won't be that useful to browser based clients, perhaps that'd be the way to go.
- masklinn 14y ago> Because it's harder to set the content-type from browsers. That's only when using HTML forms or links, TFA does not even mention the option of multiple representation of resources so it's irrelevant: there's nothing hard to adding an Accept header to an XHR.
- mnarayan01 14y agoI assume he's talking about developer discovery/exploration.
- mfenniak 14y agoBecause that approach isn't recommended anymore. In short, it's much harder to for a cache to work effectively based upon Accept & Content-Type headers than it is for it to work on the URL. For example, here's a quote from Roy Fielding: "In general, I avoid content negotiation without redirects like the plague because of its effect on caching.". In other words, content negotiation for a versioned content-type is OK... if it redirects to a URL that contains the version. httpbis, the IETF working group in charge of maintaining and developing the core HTTP spec, has deprecated content negotiation: http://trac.tools.ietf.org/wg/httpbis/ticket/81 http://trac.tools.ietf.org/wg/httpbis/ticket/81; it's still part of a separate spec (RFC2295), but it's not a core component of HTTP anymore. Why? 'HTTP content negotiation was one of those "nice in theory" protocol additions that, in practice, didn't work out.' Certainly you can still build an API that works fine using specialized content types. Versions in the URL are a pretty practical approach that work very well too.
- masklinn 14y agoDiscussed: * HTTP verbs * status codes * look of URLs * error messages Not discussed: * content types * hyperlinks Conclusion: not about REST or RESTfulness, guide about RPC-over-HTTP.
- hunvreus 14y agoI had left them out for a future post as I wanted to focus on quick guidelines to get started. Mea culpa for not mentioning them at least: will rectify in a couple days with a follow up post properly framing this.
- untothebreach 14y agoNot to mention that JSON (by itself) is not sufficient for hypertext
- masklinn 14y agoNaturally, but that's covered in "content types". Also you could always use LINK headers with whatever @rel, depending on what you're linking or how.
- bjeanes 14y agoOr, rather, REST level 2, instead of the [ideal level 3](http://martinfowler.com/articles/richardsonMaturityModel.html http://martinfowler.com/articles/richardsonMaturityModel.htm...)
- masklinn 14y agoFowler's levels are codewords for "let's call not rest rest, because everybody's already fucked it up". If an API is not hypertext-driven, it's not REST: http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hyperte... It may not be a sufficient property, but it is a necessary one.
- vivin 14y agoThe last two are usually combined to HATEOAS or semantic media-types. Most REST things I see only talk about the first 4 points, but rarely talk about semantic media-types. Until then, it truly isn't REST; only RESTlike.
- buro9 14y agoTime, content types and showing the developer (and user) what's possible (HATEOAS)... Time Using UNIX time may be easier for a developer, and I do concede that point, but by using UNIX time you're doing a few things: 1) You're exposing some internal logic or data structure of the system in the resource 2) You're removing information on time zone 3) In some circumstances where greater precision is needed you're precluding the use of nanoseconds I know that some languages don't naturally handle ISO8601 dates with nanoseconds, but I do think that's the best format. YYYY-MM-DDTHH24:MI:SS.NNNNNNNNNZ With that format one can keep a deeper knowledge of timezone, of precision, of human readability (and JSON.org does say that JSON is easy for humans to read). Content Types Whilst it may be pragmatic to not plumb the depths of custom content types they should at least be mentioned and made compulsory even if they aren't typed to a detailed level of specificity. Content Type: application/json is fine, so long as it's used and paid attention to. Capabilities HATEOAS and meta-data... I like to encourage developers to explore what's possible in the API by showing them the actions that they can do on an item, and their permissions. As in... if they can update something, show them how by telling them the URL. The API should ideally not lead a developer to an action that they couldn't perform. Minor Points I generally prefer to restrict the possible HTTP status codes and publishing that list so that a developer implementing against the API can build a generic wrapper, know what to expect and take care of handling it. Which means, sometimes I will generalise a response rather than using a status code in one place and one place only. I'm not so sure on using verbs for special actions like search, 'q' is a well understood part of the 'query string', and I'd make that just an optional parameter on the pluralised collection URL. But... perhaps that's just a bad example.
- BerislavLopac 14y agoOn your "Capabilities" point, if it's REST you don't need to tell them the URL. With REST, the URL for a resource never changes.
- buro9 14y agohttp://timelessrepo.com/haters-gonna-hateoas#hateoas http://timelessrepo.com/haters-gonna-hateoas#hateoas It shows in the example: <entry> <id>1337</id> <author>Steve Klabnik</author> <link rel = "/linkrels/entry/newcomment" uri = "/entries/1337/comments" /> <link rel = "self" uri = "/entries/1337" /> </entry> But I would go further and suggest that whether to show those shouldn't just be based on what the API can do, but what the client (and perhaps user controlling the client) can do. As in... if they can read but not create, then show the "self" link but not the "newcomment" link. Thus we're not just saying "our API has these endpoints", we're saying "you can do this".
- AznHisoka 14y agoWhat's a RESTful way of authenticating users when you will also have a web app that will use the same API? Should there be just OAuth for API users, and cookies/sessions for web users, or is there a way to make both use the same authentication method?
- julien_c 14y agoWhy don't you use OAuth for your Web app as well?
- zedr 14y agoIsn't a Web site also a Web service? Following REST, should't the Web site and API be unified, with the same resources being consumed by both humans and robots (by varying the representation)? I posted this question on Stackoverflow a few weeks ago: http://stackoverflow.com/questions/15360415/should-a-web-site-also-be-a-web-resource http://stackoverflow.com/questions/15360415/should-a-web-sit...
- polack 14y agoPOST for update and PUT for create, not the other way around. EDIT: Wow. A lot of people who think I'm wrong. I agree with you that its not the whole truth, but I think its more true (for most cases) than what the article say.
- stuffihavemade 14y agoNo, POST for create and PUT for update is correct. PUT is supposed to be idempotent.
- polack 14y agoWell, if you know the full object to save I would use PUT. If you expect the server to fill in ID or something similar I would use POST. But why use PUT for update? Dont you have to post the entire object (all fields) with a PUT? So if you just want to update one field a POST is more appropriate?
- stuffihavemade 14y agoYou could use PATCH instead (which Rails will be using in 4.0).
- icebraining 14y agoNo, PUT can be for creating too, if the client already knows the final URL. From the spec: If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI. If a new resource is created, the origin server MUST inform the user agent via the 201 (Created) response.
- untothebreach 14y agostuffihavemade is correct. Also, generally a POST request is made to some kind of "resource creating" URI, which includes the URI for the newly-created resource in it's response. A PUT request is typically made to the URI of an existing resource.
- zedr 14y agoEncoding the version number in the URL may be convenient, but certainly does not follow REST. Consider the following pair of URLS: /api/v1/posts/1 /api/v2/posts/1 This implies out-of-band information that these two resources are actually the same entity. The version number belongs in the `Accept:` field of the HTTP request headers; for example `Accept: application/json; version=2`
- buro9 14y agoThat's OK, the title of the article says "RESTful" and not "REST". Pragmatically I've found through experience that most developers tend to be more comfortable thinking of URLs and general content types.
- mnarayan01 14y agoAccept: application/json; version=2 Is that a standard-compliant media type? `version` doesn't appear to be associated with application/json in the IANA media type registry, and I couldn't find anything definitive about adding arbitrary parameters.
- masklinn 14y agoI'm pretty sure parameters are not limited to those provided by IANA (just as media types are not necessarily IANA-registered incidentally) e.g. RFC2616's Accept doc shows a `level` parameter to text/html which is not IANA-specified (and seems entirely unspecified)
- mnarayan01 14y agoYea I saw the use of level in the example but didn't think to look at the text/html spec to see if it was there. That would seem to imply that you are correct (though it would be nice if there were an explicit answer on this, if only for purely OCD reasons). > just as media types are not necessarily IANA-registered incidentally Per RFC4288 I believe they must be if they are in the standard tree (i.e. the name does not contain a '.' or an 'x-' prefix for historical reasons).
- 14y ago
- jrochkind1 14y agoagree with everything except... unix time, really? Unix time has all sorts of weird potential problems, including year 2038, historical inconsistent handling of leap seconds[1], more. ISO8601 or bust! Other than that, yes, I think there are things about REST and REST-like API's that are not clear and subject to debate about best way to do it -- but none of them are mentioned in this post, these are the floor, yep. [1]http://cr.yp.to/proto/utctai.html http://cr.yp.to/proto/utctai.html
- brown9-2 14y agoI've found that it is very helpful to include some sort of pseudo-unique "Incident number" in error responses which you also log in the server's log along with any exception/error details. This makes it very easy then to correlate issues reported by users with the actual errors/requests in the log.
- thelarry 14y agoEvery few months people start an argument about post vs put vs patch and versioning in the url vs some header. I think a lot of developers aren't fully aware of PATCH and making put actually fully replace an object can be dangerous. This probably especially bad if you use some schemaless db. For versioning, I like to support both. Let the user do what makes them happy. Not really that hard to support URL and header...
- bothra90 14y agoAnother article where the author thinks(confuses?) REST and CRUD have a one-to-one mapping? Ref: https://jcalcote.wordpress.com/2008/10/16/put-or-post-the-rest-of-the-story/ https://jcalcote.wordpress.com/2008/10/16/put-or-post-the-re...