10 ms·
How Not to write a "REST" API
- adamjernst 15y agoYeesh. According to this chart: http://nordsc.com/ext/classification_of_http_based_apis.html http://nordsc.com/ext/classification_of_http_based_apis.html Sharefile is not even a HTTP API (since it doesn't use HTTP methods correctly). For security purposes, authentication can be further increased by a POST of the "username" and "password" through the HTTP Headers as individual headers instead of the query string. POST https://subdomain.sharefile.com/rest/getAuthID.aspx https://subdomain.sharefile.com/rest/getAuthID.aspx HTTP/1.1 Content-Type: application/x-www-form-urlencoded password: yourpassword username: email@address.com What... I don't even...
- alexchamberlain 15y agoThat is spectacularly bad, I wonder if they know RFCs exist.
- artanis0 15y agoAs someone just starting to learn about secure restful web services: what is wrong with this security implementation of theirs?
- deleted 15y ago[deleted]
- anty 15y agoUsername and password are still sent in plain-text. You could use HTTPS to make the communication secure.
- SomeOtherGuy2 15y agoNo they aren't sent plain-text: >https://subdomain.sharefile.com/rest/getAuthID.aspx https://subdomain.sharefile.com/rest/getAuthID.aspx Notice the https. The facepalm is just that there's no additional security in using POST vs GET.
- carbocation 15y agoPOSTed values won't show up in typical server logs, whereas with GET their plaintext password would normally be logged on every request. And POST over HTTPS keeps the POSTed values hidden from those who might listen, whereas with GET over HTTP it would just be out there in the URL.
- SomeOtherGuy2 15y agoYou have no way of knowing what they log and don't log. If their server logs are compromised, you should be assuming their username/password database was as well. And HTTPS requests are encrypted. The whole request, including the "GET /someurl&password=s33krit HTTP/1.1" part. As I said, using POST doesn't add any additional security to this.
- carbocation 15y agoI agree with your concerns. But my comment was talking about "typical server logs" and HTTPS-POST vs HTTP-GET, while yours is addressing different issues.
- SomeOtherGuy2 15y agoI addressed why what gets in logs doesn't matter: if their server is compromised you have to assume you are boned anyways. And I don't understand why is your comment would be talking about "HTTP-GET"? The API in question is dealing with HTTPS for both GET and POST requests.
- cristoperb 15y agoI don't understand why your comments pointing out details of the http spec and common-sense security considerations are being downvoted. I guess they are coming across as overly 'stident'? Anyway, I've found them helpful. Thanks.
- tptacek 15y ago
- alexchamberlain 15y agoIt's not compliant with the HTTP standard.
- SomeOtherGuy2 15y agoIn what way is it not compliant?
- alexchamberlain 15y agoCustom headers should be prepended with "X-". Also, the top line should read POST rest/getAuthID.aspx HTTP/1.1 Correction: Use of "X-" has been depreciated in a draft resolution. Edit: As mentioned below, it isn't compliant in its use of the verbs (GET/POST etc).
- SomeOtherGuy2 15y agoCustom headers do not REQUIRE a prefix. So the lack of prefix does not make it non-compliant. In fact, the HTTP RFC doesn't even say they SHOULD have a prefix. And RFC822 which defines headers only says that protocol mandated headers MUST NOT be prefixed with "X-". Also, there's a draft proposal to deprecate the "X-" header prefix as it does more harm than good: http://tools.ietf.org/html/draft-ietf-appsawg-xdash-02 http://tools.ietf.org/html/draft-ietf-appsawg-xdash-02 Second, absolute URIs are perfectly valid, all HTTP/1.1 servers MUST accept them: http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1 http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1
- nickyp 15y agoIt's not 'compliancy' as much as they're reinventing the wheel. REST was born out of a philosophy that the HTTP protocol already solved much of what you wanted to do. HTTP not only solved this, but solved this a long time ago and with 'great success' (aka The Interwebs ;-) - Authentication mechanism - Operations (CRUD) -> GET, PUT, POST, DELETE, ... - Caching -> Use HTTP caching mechanisms... - Resources -> URL's - Formats -> mime-types + use a HTTP Accept: header - ... They reinvent the wheel on many of the bullet points above: custom operations, custom format handling, custom authentication mechanisms, ... That's why this really is one of the worst implementation of an 'RESTful' API
- stevejalim 15y agoIf you're learning about REST, do it right and make this book your bible - it's brilliant: http://www.amazon.com/Restful-Web-Services-Leonard-Richardson/dp/0596529260a http://www.amazon.com/Restful-Web-Services-Leonard-Richardso...
- dlokshin 15y agoCorrect link: http://www.amazon.com/Restful-Web-Services-Leonard-Richardson/dp/0596529260 http://www.amazon.com/Restful-Web-Services-Leonard-Richardso...
- stevejalim 15y agoWhoops, sorry!
- danellis 15y agoWhy should that particular book be the bible? I haven't read it, but I've flicked through it and seeing things like the suggestion that clients should "construct" URLs made me doubt its worth. Shouldn't Fielding's original thesis be the bible?
- stevejalim 15y agoOk, maybe bible was used to loosely. In my experience, I found it a well written, well balanced, useful primer for real-world development of RESTful web services that also has enough depth to make it a reference I've returned to since. That's better.
- peterwwillis 15y agoIt's wrong because: 1. Passing creds via GET will show up in server logs. 2. The way REST works, you don't want to put anything in a GET which will change anything on the server (which includes generating an auth token). POST is the standard here. edit It's better that they support POST for the auth creds in a header, but they should still be using HTTP standard authentication methods and return a 401 if unauthorized. Also, look for already complete solutions for what you want. The whole point of REST is that you don't need to create all these query string parameters or put stuff in headers - the HTTP specs already include most of this functionality. For example HTTP already includes several authentication mechanisms[1], as does TLS[2], which are more secure (and standard!) than a form-based login. [1] http://en.wikipedia.org/wiki/Digest_access_authentication http://en.wikipedia.org/wiki/Digest_access_authentication [2] http://en.wikipedia.org/wiki/Secure_Remote_Password_protocol http://en.wikipedia.org/wiki/Secure_Remote_Password_protocol
- danellis 15y agoI once worked with a major product from a large company that hilariously used these two HTTP headers: passwd: yourpassword quoted-passwd: "yourpassword"
- vyrotek 15y agoAs a .Net developer I am a little bit ashamed to see the .aspx extensions in this API. We're not all like that... I swear. You believe me right? Sadly, I can imagine how they got to this point. They were tasked to create an API and they did it with the knowledge and tools that they had.
- RexM 15y agoYes, I can see how they got where they did, too... When all you have is a hammer, everything looks like a nail...
- shanemhansen 15y agoEngineers like us can be such snots sometimes. If as a culture we want people to build great RESTful apis and a company attempts to do so, public shaming isn't the answer. But. Their homegrown text serialization format is pretty wack. They couldn't just use CSV?
- vyrotek 15y agoAgreed. I was mostly hoping to mitigate any conclusion that the design was a result of them being .Net developers. :) Luckily there are some constructive comments in this post which point out some valid concerns. This is a good chance to share opinions and learn a bit. Unfortunately there are a lot of developers out there who are tasked with projects and have no one in-house with experience. I was in that boat and it took developing and maintaining a lot of bad APIs to learn what made a good one.
- jcromartie 15y agoI don't think they attempted to build a REST API. They just built a weird API and said "oh hey we'll call this REST, that's cool right?"
- freshhawk 15y agoThat culture of being "snots" comes from engineers in the real world. The one where this kind of attention to detail means buildings fall on people. I agree that maybe it's not necessary to carry over that cultural legacy to the internet, although so far it's worked pretty well. If social pressure (public shaming) isn't the answer then what kind of pressure should be used? Public shaming is a pretty civilized way to enforce rules when you have no top down control that dictates those rules, I can't think of any alternatives that would be less harsh.
- eli 15y agoMost of the proprietary APIs I've had to work with were just as bad. Sometimes I wonder if the NDA they make you sign before seeing the API documentation is so that you won't be able to show anyone else how bad it is.
- bryanh 15y agoPoignant observation. I'm currently working with an unnamed credit API and all calls, regardless of status, return 200. Options can be strung together in single GET parameter. All calls resolve to a single URL and the method is chosen get a GET param (which variant of that method is yet another param). And a person's information can be passed in via any slew GET params, or as POST'd XML. Its a mess... anyone up for a Stripe of the credit/authentication world?
- eli 15y agoI once spent weeks writing a wrapper for a particular service provider's API (which they charge a premium to access). Every request was a POST and every response was 200. In one function, timestamps were represented by a unix epoch, but others had the same field encoded as ISO 8601. The XML returned was not guaranteed to be well formed. Etc. The kicker is that they declined permission to open source my wrapper because "the API is proprietary."
- bryanh 15y agoSounds familiar. I wonder if the same masochistic fools wrote them both...
- lvillani 15y agoLooks like an RPC-style API with multiple endpoints + custom authentication scheme.
- vyrotek 15y agoI was going to mention this. If this documentation completely removed the word 'REST' would we have cringed as bad?
- Torn 15y agoProbably not, but after seeing how nice REST API's can be with sensible url mappings, HATEOAS, HTTP methods as verbs, etc. it's almost insulting for sharefile to call it RESTful (presumably because it can return JSON?). Off the top of my head: - API method urls are all the same .aspx, regardless of method used - All calls are sent as GET (ignoring the whole point of HTTP methods in REST) - No HTTP method codes as responses for automated parsing - Custom authentication putting credentials in URL or in headers instead of relying on proven HTTP auth schemes we've been using for years (basic, form, etc) - Return format is done with get arguments instead of HTTP content negotiation in headers (not so bad) They've completely missed the boat here.
- euroclydon 15y agoThe query string and headers ARE encrypted in https. And forms auth, that's just a post and a cookie. You can't require API clients to support cookies.
- padobson 15y agoBut, and excuse me if I'm wrong on this I'm looking for clarification, you should be forcing API clients to sign their requests with some sort of token - which might as well be a cookie. The difference being that a browser keeps track of the cookies for you, and any other client will have to keep track of any auth info itself (in a sqlite DB, xml file, held in memory, etc)
- Eduard 15y agoWhat else is flawed with this API? I'd be nice to have a "Dos and Don'ts in REST API design", with the Don'ts exemplified with Sharefile's API.
- breaker05 15y agoI'd like to know the same thing. Aside from everyone complaining that they used the term RESTful wrong, is there anything really wrong? It authenticates securely over HTTPS so I am confused what is wrong. Saying it's not complaint I don't really follow either. Thanks for any help.
- ps2000 15y agoI guess it's also a matter of taste. In any case, my taste is this: RESTful APIs usually represent CRUD operations, each of these letter can be beautifully mapped to request types: - CREATE -> POST - READ -> GET - UPDATE -> PUT - DELETE -> DELETE Second point: {error: false, value: actual_data} If we have an error variable, what is the HTTP error code then good for? Normal Web Servers use the HTTP error codes for a reason. Besides using standard webframework a json containing only "actual_data" means less code, less errors and so forth... Third point: URLs should represent the hierarchy: GET /users/43/bookmarks/32442?... is much more beautiful and straight-forward to work with than /api_handler.exe?user_id=43&bookmark_id=32442&operation=get... Regarding authentication: use a secret API key, that's simple and secure. Everybody does that, from small services to multi million user services like facebook. As a hint: read the dissertation of Roy Fielding who "invented" REST. In my opinion REST means to exploit HTTP as far as possible instead of using any custom conventions.
- SoftwareMaven 15y agoI agree with most of what you said, but mapping CRUD directly onto the verbs is perhaps a little simplistic. See http://jcalcote.wordpress.com/2008/10/16/put-or-post-the-rest-of-the-story/ http://jcalcote.wordpress.com/2008/10/16/put-or-post-the-res... for a discussion on it. The very short version is that idempotency is important, POST must be used for non-idempotent updates, and there is no reason PUT can't be used to create if you know the ID of the resource.
- padobson 15y agoFor discussions sake, here are the constraints on REST from wikipedia: http://en.wikipedia.org/wiki/REST#Constraints http://en.wikipedia.org/wiki/REST#Constraints
- shearn89 15y agoAs @artanis0 (kind of) mentioned, it'd be great to see a HN post sometime soon called "How to write a good 'REST' API". Or even just some links to good tutorials that could get me (and others) started? I've recently built a DB driven site that could possibly be extended with an API, and it's a good chance to learn something with a purpose behind it!
- poutine 15y agoIt's pretty straight forward, just do the following: - Use HTTP verbs: GET to retrieve one or more objects, POST to create a new object, PUT to update an existing object, DELETE to remove an object. - Address objects by collection and by individual object: /users/#{user_id} is a specific user you can PUT, GET or DELETE. /users is where you POST to in order to create a new user. - Use HTTP codes to return the result back to the client (ie HTTP 200 when you get an object, 201 when you successfully POST an object, 404 when you try to GET/UPDATE/DELETE an object that doesn't exist). - I find it good form to return objects in JSON with the type of object at the top of the data structure, ie {:users => [ #array of users here ]} or {:user => { #single user }} - Use OAuth or some sort of token system for authenticating the calls, don't use HTTP Auth. You can get pretty anal about things but if you follow the above you'll have a cleaner API than 90% of the API's out there.
- SimHacker 15y agoA big dumb mistake this api makes is sending commands and object ids via query parameters, instead of making them part of the url. The url should look like a file path that addresses an object -- the path of the objects shouldn't be in a query parameter. Especially when the object you're addressing is a file that has a logical location specified by a path.
- jcromartie 15y agoREST is not about pretty URLs. In fact, you could build a great RESTful API with pretty hideous looking URLs.
- 15y ago
- tlack 15y agoWe're so spoiled that now we're complaining about the APIs we do get? I would have died for stuff like this ten years ago when using data from other sites involved scraping, harassment, and trickery. Just like not everyone can produce a beautiful, accessible, standards compliant website, not everyone can produce a perfectly REST API. I give them kudos for opening up their system, or at least attempting to.
- amackera 15y agoThough you make good points, perhaps Sharefile shouldn't claim that their API is RESTful when in fact it clearly isn't. There's nothing wrong with having a non-RESTful API, apart from it being far less clear and understandable as REST.
- SoftwareMaven 15y agoFor many people, REST == ! SOAP. There is nothing more to it than that. And because REST is more an architectural framework than a protocol (remember, the protocol is HTTP), it's hard to teach them otherwise.
- TylerE 15y agoThere is a word for those people. That word is "wrong". Don't fall victim to the tyranny of the masses.
- lysol 15y agoKudos for the API, but lying about it being REST can cost developers significant time or at least blow estimates. If they butcher their API this badly, would you really put stock in the backend being written in any kind of sane fashion? Would you trust it?
- bsenftner 15y agoI don't hear people mention Drupal much here at HN. I assumed it was the learning curve; but anyway.. I point your interest over at https://drupal.org/node/783460 https://drupal.org/node/783460 where the Services 3.0 module's REST API development framework is demonstrated with an example of creating a simple RESTful CRUD service. For ambitious WebApps & WebAPIs, Drupal provides great scaffolding for development. And it looks like the Drupal8 branch, a few years away, is 'headless' as in being configurable to only be an API endpoint with no "web site" necessary.
- maratd 15y agoUsing Drupal to create a RESTful API is like using a tank to hammer in a nail. It takes about 50 lines of code to write a simple RESTful API in pure PHP. Take a look at http://www.recessframework.org/page/towards-restful-php-5-basic-tips http://www.recessframework.org/page/towards-restful-php-5-ba... to learn how to get started. Also, the dude who wrote that has a framework that is built around REST. You don't really need it though.
- Scybert 15y agoWhy do nerds constantly need to point to other people's failure to feel good?
- breaker05 15y agoSo this whole thread could have been averted if the term REST was removed from this API it sounds.
- sfdev 15y agoDone.
- jtchang 15y agoHey look...an API with DOCUMENTATION! You guys are spoiled. In my day we had to guess what parameters to send.
- tlrobinson 15y agoWhile this may be particularly bad, very few "REST" APIs actually follow all of the principles of REST.
- ww520 15y agoSeeing their API just reminds me something. What is a good way to deal with methods that don't fit in the usual HTTP verbs (GET/POST/PUT/DELETE), like Rename, Grant, Revoke in their case? In the past I've simply extended the uri to indicate additional methods like, POST /user/foobar/grant. I wonder whether putting those methods as additional HTTP verbs would be better. Edit: extending HTTP verbs might not work too well with some firewalls/NAT that filter out non-standard verb requests.
- regularfry 15y agoDefining additional verbs is certainly allowed, bit it's worth looking to see if your operations would be more easily mapped to a different resource model. For instance, a "rename" operation might work well as a PUT to a foo/name endpoint.
- akazackfriedman 15y agoBy how not to write a "REST" API you mean don't use Microsoft right? Sorry, I couldn't resist a good .NET bashing.