
How Not to write a "REST" API - reinhardt
http://api.sharefile.com/rest.aspx
======
adamjernst
Yeesh. According to this chart:

<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> HTTP/1.1

Content-Type: application/x-www-form-urlencoded

password: yourpassword

username: email@address.com_

What... I don't even...

~~~
artanis0
As someone just starting to learn about secure restful web services: what is
wrong with this security implementation of theirs?

~~~
stevejalim
If 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-
Richardso...](http://www.amazon.com/Restful-Web-Services-Leonard-
Richardson/dp/0596529260a)

~~~
dlokshin
Correct link: [http://www.amazon.com/Restful-Web-Services-Leonard-
Richardso...](http://www.amazon.com/Restful-Web-Services-Leonard-
Richardson/dp/0596529260)

~~~
stevejalim
Whoops, sorry!

------
tlack
We'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
Though 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
For 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
There is a word for those people. That word is "wrong". Don't fall victim to
the tyranny of the masses.

------
eli
Most 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
Poignant 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
I 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
Sounds familiar. I wonder if the same masochistic fools wrote them both...

------
shearn89
As @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
It'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
A 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
REST is not about pretty URLs. In fact, you could build a great RESTful API
with pretty hideous looking URLs.

------
vyrotek
As 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
Yes, I can see how they got where they did, too... When all you have is a
hammer, everything looks like a nail...

~~~
shanemhansen
Engineers 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?

~~~
freshhawk
That 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.

~~~
shanemhansen
According to some the latest hn posts about facebook, in our industry you're
doing something wrong if the building doesn't fall over from time to time ; ).

Public shaming can be a good idea, especially on people who are knowingly
breaking the rules and holding back progress (See IE6).

However, I'm just glad people are creating APIs, especially because basically
no one gets REST right anyways (Hint: if you can't click around your api in
firefox with the JSONView extension, it's probably not RESTful).

------
lvillani
Looks like an RPC-style API with multiple endpoints + custom authentication
scheme.

~~~
vyrotek
I was going to mention this. If this documentation completely removed the word
'REST' would we have cringed as bad?

~~~
Torn
Probably 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
The 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
But, 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)

~~~
csears
> sign their requests with some sort of token - which might as well be a
> cookie

Using a token to sign requests is certainly a good idea, but you probably
don't want to pass the token around using a cookie, even over HTTPS. Many
browsers don't enforce good cookie security and will transmit cookies in the
clear if an attacker can redirect the browser to a non-HTTPS URL on the same
domain.

------
Eduard
What 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.

~~~
jherdman
There are a few comments in this post that touch on the flaws of this API.
Here's the gist:

1\. HTTP methods are improperly used. The documentation states "All API calls
should be sent as a GET HTTP request". GET is used to retrieve resources, and
should be cacheable. It should NEVER change the state of a resource. Yet we
see in that it's used to delete, create, and modify resources! Examples:

GET <https://subdomain.sharefile.com/rest/folder.aspx?op=create..>.

GET <https://subdomain.sharefile.com/rest/file.aspx?op=delete>

These _should_ be as follows:

POST <https://subdomain.sharefile.com/rest/folder.aspx>

DELETE <https://subdomain.sharefile.com/rest/file.aspx>

HTTP verbs have specific semantics that allow for intelligent, scalable
architecture.

2\. Individual resources are not identified by an unchangeable URI. Let's say
I want a folder:

GET
[https://subdomain.sharefile.com/rest/folder.aspx?op=get&...](https://subdomain.sharefile.com/rest/folder.aspx?op=get&id=123)

Nope. This is more RESTful:

GET <https://subdomain.sharefile.com/rest/folder/123>

Two things to note: 1) no 'aspx' bullshit, that's implementation and shouldn't
be visible to the user, and 2) the ID is in the URI itself as opposed to the
params. URIs should seldom, if ever, change. Parameter names may change, URIs
shouldn't.

3\. Violation of content type retrieval. Let's say I want a folder as XML:

GET
[https://subdomain.sharefile.com/rest/folder.aspx?op=get&...](https://subdomain.sharefile.com/rest/folder.aspx?op=get&id=123&fmt=xml)

Wrong. This is the request I should be sending as a curl:

curl <https://subdomain.sharefile.com/rest/folder/123> -H 'Accept: text/xml'

Note that I'm using the Accept header. This allows for flexibility in
accessing my resource. With any luck, the server will give me an XML file, and
its content type should be "text/vnd.sharefile+xml" (vendor specific content
types are best).

4\. No link relations in the body. I'm mostly assuming this because I haven't
seen sample response bodies, but almost _no one_ does this even though is a
crucial aspect of a RESTful service. RESTful services describe the
relationship between resources. Suppose I have an ordered collection of files.
When retrieving a file, it should describe its relationship in this ordered
collection. This is done either via the LINK header, or some sort of scheme in
your response body (e.g. JSON Schema describes 'link' attributes).

A pretty good RESTful API is Github's (see <http://developer.github.com/>). If
you'd like to learn more, I highly recommend "REST in Practice" by Webber, et
al ([http://www.amazon.ca/REST-Practice-Hypermedia-Systems-
Archit...](http://www.amazon.ca/REST-Practice-Hypermedia-Systems-
Architecture/dp/0596805829/ref=sr_1_1?ie=UTF8&qid=1328113416&sr=8-1)).

~~~
arethuza
Your second point really isn't RESTful - URIs should be opaque and "Servers
must have the freedom to control their own namespace.":

[http://roy.gbiv.com/untangled/2008/rest-apis-must-be-
hyperte...](http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-
driven)

~~~
jherdman
Thanks for the info! I love learning things :)

------
jtchang
Hey look...an API with DOCUMENTATION!

You guys are spoiled. In my day we had to _guess_ what parameters to send.

------
ww520
Seeing 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
Defining 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.

------
tlrobinson
While this may be particularly bad, very few "REST" APIs actually follow all
of the principles of REST.

------
breaker05
So this whole thread could have been averted if the term REST was removed from
this API it sounds.

~~~
sfdev
Done.

------
padobson
For discussions sake, here are the constraints on REST from wikipedia:
<http://en.wikipedia.org/wiki/REST#Constraints>

------
bsenftner
I 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> 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
Using 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-ba...](http://www.recessframework.org/page/towards-restful-php-5-basic-
tips) 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.

------
akazackfriedman
By how not to write a "REST" API you mean don't use Microsoft right? Sorry, I
couldn't resist a good .NET bashing.

