top | item 4437431

How RESTful is Your API?

97 points| housecor | 13 years ago |bitnative.com

56 comments

order
[+] chime|13 years ago|reply
I've written probably half a dozen unrelated apps that call REST APIs and I think they all implemented REST differently. Some treat PUT as insert while POST as update. Some treat POST as insert, PUT as insert/update. Some return 201 when insert was successful, some return 200 whenever anything is successful. Some issue tokens, some authenticate using headers.

Just last night I wrote some code to auto-create Trello cards and assign them to a specific list. The https://trello.com/docs/ seem fairly decent but what they don't tell you is that POST is insert, PUT is update. Moreover, while you can assign a due date via PUT ( https://trello.com/docs/api/card/index.html#put-1-cards-card... ), you cannot assign one via POST ( https://trello.com/docs/api/card/index.html#post-1-cards ). So if you want to create a card with a due date, you have to POST, read ID, then PUT the due date to /card/id.

The problem with people trying to be RESTful is that they pay too much attention to stuff that doesn't matter (71 status codes) instead of stuff that really matters (simplify complex insert/update). I'd rather have Trello return 400 on errors and provide a text description than use one of the 30+ 4xx errors. And I'd rather have them accept due date when inserting a card. Trying to conform to REST's standards is like trying to be XHTML compliant. Great, your site validates. But you're still using white font on yellow background!

Be as RESTful as you need to be. But more than that, be useful and sensible. Don't make me call your server six times to make one valid GET request.

[+] alexchamberlain|13 years ago|reply
"POST is insert - PUT is update" is the norm and HTTP compliant way of doing things. Why not reach out to Trello and ask why you can't do the due-date on POST?
[+] regularfry|13 years ago|reply
I'm surprised nobody has mentioned the Richardson Maturity Model: http://martinfowler.com/articles/richardsonMaturityModel.htm.... It's explicitly for discussing and characterising the degree of RESTfulness of a given API.

For my money there's nothing actually wrong with implementing, say, a level 1 API, as long as you don't claim anything higher. It'd be very nice for everyone to be at level 3, but obviously the tooling isn't there yet to support it universally.

[+] davedx|13 years ago|reply
I hadn't seen it before, but I like it. Practical and specific. I think you could actually use this when proposing time/cost estimates for web service development.
[+] yiz|13 years ago|reply
that is a great article. makes a strong argument for the point of hypermedia links too.
[+] ljd|13 years ago|reply
There is much ado in the REST world about whether one API is more restful than another. For us, our REST API was designed from our experience as consumers of other REST API's. Our whole philosophy wasn't about what was true-rest but rather, what was both consistent and easy to learn.

We do fancy stuff like send back HTTP codes that aren't always invited to the cool HTTP code parties like, "Payment Required" and we used "Accepted" on a PUT (Update).

Also, while we know that a rest API should be entirely self documenting we found it more practical to create a GitHub account explaining every call with sample code in variety of languages, all doing the same thing: sending JSON via a REST library.

We are a B2B product and reducing any barriers to enriching our clients is a must. We've worked on big dev teams and understand that if we want our product to get on the next sprint we need to make sure that they can copy and paste our code into their software and it'll work. It's just the nuts and bolts of business.

I would accept data on floppy disk duct taped to carrier pigeons if that was the easiest way for clients to interact with our algorithms. Fortunately for us, being "pretty" rest-y was a better fit for everyone.

[+] Natsu|13 years ago|reply
> Why Deviate? > Although REST prescribes using HTTP GET, PUT, POST, and DELETE verbs for CRUD operations, some clients can’t generate the less common PUT and DELETE requests. In addition, some overzealous firewalls block PUT and POST. Thus, some RESTful APIs accept all requests via HTTP GET and place the HTTP verb in the querystring. For example, to delete user 124, the GET request would be for the following URI: /users/124?method=delete This technique is especially common in Ruby circles. Another benefit of this approach is all requests can be easily generated and manipulated in the address line of any browser.

This is a very bad idea for something like delete. It's Daily WTF material:

http://thedailywtf.com/Articles/The_Spider_of_Doom.aspx

Any firewall that blocks POST requests but not GET is a WTF in and of itself, for that matter.

[+] kodablah|13 years ago|reply
Some people resolve this with the X-HTTP-Method-Override header which I believe is a lot more clean. This is very helpful in situations where certain strict REST clients don't support PATCH (the underrated verb to help with partial updates).
[+] tomchristie|13 years ago|reply
Overloading the request method using URL paramaters, as the author mentions is a bad idea. What is accepted behavior, is overloading the request method using hidden form data in a POST request.

The later is what Rails actually does - http://guides.rubyonrails.org/form_helpers.html section 2.4

"There are two noncontroversial uses for overloaded POST. The first is to simulate HTTP's uniform interface for clients like web browsers that don't support PUT or DELETE" - RESTful Web Services, Leonard Richardson & Sam Ruby.

[+] housecor|13 years ago|reply
Great point Natsu. I agree and have edited my post accordingly.
[+] deno|13 years ago|reply
> Notice what this doesn’t include? XML and JSON. Neither offers a native way to convey a hyperlink.

Both XML and JSON offer standard ways to include hyperlinks. XLink[1] and JSON Schema[2], respectively. Not to mention you can include hyperlinks in headers[3].

The problem with “hypermedia” is that the concept is completely useless without common nouns and verbs. So it’s fine if you can fit your application to use WebDav or AtomPub plus extensions, but for a custom API there’s no point.

[1] https://en.wikipedia.org/wiki/XLink

[2] http://json-schema.org/

[3] urn:ietf:rfc:2068 (https://tools.ietf.org/html/rfc2068#section-19.6.2.4)

[+] pbreit|13 years ago|reply
I found the cheat sheet annoying. Doing all requests over GET is not acceptable, especially deletes. The jury is still out on GET/POST vs GET/POST/PUT/DELETE. I don't see any problem with file extensions. After all, that's how the web has worked from the very beginning. Hard to do discovery without any guidance on format. Version numbers are not very RESTful and I don't care for them. Spend a little extra design energy to avoid the need for versioning. Static URLs are sort of necessary absent better discovery mechanisms. He skips the notion of returning a resource address as a "Location" upon creation.
[+] jcdavis|13 years ago|reply
Annoying or not, its a fairly accurate description of the state of APIs. I agree about the all GET setup, although I've never actually seen that in the wild (seems pretty dangerous). I personally have no problem with using POST for all endpoints with side effects, though opinions certainly differ there.
[+] davedx|13 years ago|reply
Because a URL defines one resource in REST, so strictly speaking, /path/resource.json and /path/resource.xml are different resources using REST.

Content-negotiation is what people should use to specify format.

[+] housecor|13 years ago|reply
pbreit - Point taken on using only GET. I have edited the article accordingly.
[+] davedx|13 years ago|reply
Dramatic, and makes broad unsubstantiated claims about API's "in the wild", but the details are right. His most important point that we as API writers can work on is the "discovery" part. Hardly anyone is doing HATEOAS [1]. I think the reason for this is that if you write a public API, you're going to document it well (or nobody will use it), and good documentation kind of alleviates the need for in-service discovery.

[1] http://en.wikipedia.org/wiki/HATEOAS

[+] lmm|13 years ago|reply
I still don't see the value proposition for HATEOAS. Writing a client that can use an API that it doesn't understand seems impossible, so I can't see how discovery is ever going to work. To my mind HATEOAS represents the very complex over-engineering that REST was originally a reaction against.
[+] csulok|13 years ago|reply
In service discovery is just convenient. With SOAP libraries, using a web service is as easy as 2-3 lines of code. The library handles loading the wsdl file, generating functions with appropriate parameters, sending requests and parsing response and exception handling. Without this ability, it's a lot more code.

It's not necessarily harder, but it's more code nevertheless.

[+] sopooneo|13 years ago|reply
The big question I almost never see addressed: Why would true REST be worth pursuing anyway? What's so good about it over other ways of setting up APIs?

If I recall correctly, Fielding himself says that it may be detrimental to an individual organization in the short term, but if we all do it, it will eventually help make our APIs collectively interoparable.

[+] fideloper|13 years ago|reply
This is very interesting. The idea and requirement between ease of use and full-REST implementation is definitely worth discussing.

Two Points: * Consistency could be very useful across web-services * Simplicity is exceptionally important

If all API's were created with a 'full-REST implementation', that would comply with the need (Desire?) for consistency, however it would not necessarily be easier.

What might be "hard": * Some limitations (firewalls, lack of knowledge) on PUT and DELETE * The debate on when to use PUT and DELETE * Editing headers to request content type (xml vs json etc)

So the big question seems to be: What is the mix between consistency and ease of use?

Perhaps we can be full-on REST but then make it easier with code libraries?

[+] regularfry|13 years ago|reply
Having spent a while now working on a project with a RESTish API, I can say that I'm really regretting not pushing harder for hypermedia controls earlier. It would have made pushing upgrades out a lot simpler.
[+] shimonamit|13 years ago|reply
Easier for you, that is. The problem with HATEOAS is that it requires commitment on both parties (server and client) to that convention. For the client developer that means no hard coding changing URLs. But they will, and you'll be to blame when your server changes break their code. You'll say "but you didn't HATEOAS" and they'll say "my app is broken, fix your API now" and you... who wants to go there?
[+] lucisferre|13 years ago|reply
This is an excellent and insightful overview of REST both the good and the bad. It's the Hypermedia API problems that stand out the most to me here. It's definitely the unicorn of the whole thing.
[+] jakejake|13 years ago|reply
I spent decent amount of time and effort making my code generator/framework create a proper RESTful API, but I have to admit it is a bit tricky to figure out what is actually "proper." I feel like I was able to do a decent job with everything except the discovery service. If any PHP devs would like to contribute or just look at the API please feel free at phreeze.com
[+] cwp|13 years ago|reply
Interesting. He gives three examples of truly RESTful APIs, and Tim Bray was involved in creating two of them.
[+] rickmode|13 years ago|reply
The web page is unreadable on my iPhone. Right side is clipped; same as another post says about Android.
[+] housecor|13 years ago|reply
Thanks for the heads up! Fixed.
[+] adnam|13 years ago|reply
Perhaps you should write a strongly-worded letter to your congressman.
[+] dwood|13 years ago|reply
I once asked Tim Berners-Lee about POST vs. PUT and he told me that POST was for insert (as in posting a nntp article) and PUT was for update. That's good enough for me.
[+] bmunro|13 years ago|reply
Off topic, but the right side of the paragraph is cut off on Android.