

How to Write a Self-Documenting API - Heyzap API release - immad
http://stdout.heyzap.com/2012/03/07/how-to-write-a-self-documenting-api/

======
hinathan
I like the trick of placing something meaningful at the api root url, will use
that in the future.

    
    
      "You of course need a JSON viewer plugin to do this."
    

Why not emit your JSON slightly prettier from the server side?
[http://stackoverflow.com/questions/86653/how-can-i-pretty-
fo...](http://stackoverflow.com/questions/86653/how-can-i-pretty-format-my-
json-output-in-ruby-on-rails)

~~~
cicloid
Maybe because of the overhead on rendering time and extra bytes.

On a couple thousand requests the latency is not so noticeable. But on the
long run maybe the API user should have a plugin on the client side to do that
kind of beautification.

~~~
rglullis
Not necessarily. You would only render the prettified version when the client
has an Accept header that shows more capabilities than application/json.

Which, by the way leads to my single complaint with this API: it only renders
JSON.

To call it truly "self-documenting", I should just browse to
<http://www.heyzap.com/api/v1/> (ok, second complaint: the "v1" also belongs
in a header, not the URI) and get an HTML page describing the resource, and
links to the other endpoints. Bonus points if this HTML allows me to run the
queries with overridden parameters.

~~~
cicloid
You have a point with the rendering option from the accept header...

About the v1 versioning in the URL, I understand your suggestion. But I see
that little characteristic as a "no developer left behind" program for
developers with less experience.

Also the format as an extension for your resource serves the same purpose

------
slewis
For those who haven't seen it, the awesome django-rest-framework has built in
support for browsable, self-documenting, HATEOS APIs.

Here's a browsable example API: <http://rest.ep.io/>

Because your browser provides Accept: text/html by default you get back a nice
html page describing the result for the API root. If you send Accept:
text/json (click "json" at the bottom) you get back a json response.

You can follow the links in the html response to get to other parts of the
API. You can also click "OPTIONS" to send an OPTION request to get a
description of what you can send to that endpoint.

<http://django-rest-framework.org/>

~~~
bmelton
How well does django-rest-framework do with nested (foreignkey) resources? I
recently chose Tastypie for a project for that reason alone, but never ran
across django-rest-framework to have considered it.

Looking at the django-rest-framework API examples, that's one thing I don't
see, but is (at least for me) fairly critical.

~~~
slewis
It handles them fully. I haven't played with the many to many support, but
from having looked through the code it fully supports getting/setting many to
many relationships.

One thing that does seem to be a bit lacking is the documentation. I've used
all three django frameworks though (piston, tastypie and django-rest-
framework) and django-rest-framework wins in my book.

~~~
buss
Can you get any of those three frameworks to expose arbitrary views? One of my
biggest complaints with all of them is that they seem to only expose objects.

~~~
slewis
When you say objects I assume you mean model objects? In that case yes. I
haven't used Piston or Tastypie in awhile, but I know that you can easily
write views in django-rest-framework that aren't tied to models.

This is a bullet from the django-rest-framework page I linked above: "Modular
architecture - MixIn classes can be used without requiring the Resource or
ModelResource classes."

Here's one of the examples from django-rest-framework that is not tied to
models: [http://django-rest-
framework.readthedocs.org/en/latest/examp...](http://django-rest-
framework.readthedocs.org/en/latest/examples/pygments.html)

And also, from the Tastypie docs: [http://django-
tastypie.readthedocs.org/en/latest/resources.h...](http://django-
tastypie.readthedocs.org/en/latest/resources.html#why-resource-vs-
modelresource)

~~~
buss
I read through both of those links and I think I wasn't clear with my initial
question.

I want to expose arbitrary view methods to GET calls, not linked to any model,
and not have to write a new class for every view I want to expose. Basically I
want views to return the correct filetype (json, html, xml, etc) when
requested. This is basically making django a little more rails-like. I'm
leaning towards django-dynamicresponse currently.

I really like how the three you mentioned tie into Django's forms though, and
that's quite a feature to give up.

~~~
rglullis
Yes, you can get djangorestframework to be used without being tied to any
model, or even without tying it to a resource. In its current incarnation,
djangorestframework just follows the principle from generic class-based views.

You just define a view that inherits from djangorestframework.views.View, and
implement the action methods (get/post/put/delete) that you want. These
methods must return a dictionary, and the framework handles the part of
dispatch and render the view in the proper format.

~~~
buss
That was a really helpful answer, thanks! I'll be taking another look at
djangorestframework; hopefully I didn't miss anything else.

------
einhverfr
They are talking specifically, it seems, about RESTful and related API's, but
self-documenting API's IMO should be present at other levels of an application
too.

I would take it further and say that truly self-documenting API's should be
discoverable by software as well as individuals. This is something we have
worked on hard at LedgerSMB, doing so with stored procedures even (see
[http://ledgersmbdev.blogspot.com/2011/10/introduction-to-
sod...](http://ledgersmbdev.blogspot.com/2011/10/introduction-to-soda.html)
for more info).

Anywhere there is a connection between software, this can be a good approach.
Why limit it to the web?

------
waffle_ss
When I saw the /v1 prefix I was reminded of one of Steve Klabnik's blog
posts[1], where he gives an alternative, arguably more RESTful approach to
versioning an API.

[1]: [http://blog.steveklabnik.com/posts/2011-07-03-nobody-
underst...](http://blog.steveklabnik.com/posts/2011-07-03-nobody-understands-
rest-or-http#i_want_my_api_to_be_versioned)

~~~
immad
Hey, I addressed this point in the blog post. I disagreed with that because a)
its not self-documenting. b) On v2 the exact same URLs will have completely
different data and probably break every API consumer.

~~~
philipn
Accept header based versioning is self-documenting. I've worked on
implementing support for this in tastypie:
<https://github.com/toastdriven/django-tastypie/pull/394>

It's like this:

\--> GET /api/ Accept: application/json

<\-- Content-type: application/vnd.api.v1+json <stuff>

Then your consumers can know what version of the API they're interacting with
and act accordingly.

~~~
immad
Without reading the docs at quite depth I think it would be easy to overlook
the response content-type

~~~
umjames
What about the ability to look at API responses in a browser? You can't
normally change the request headers a browser sends without some type of
plugin.

Including the version number in the URL gets around this and even allows you
to test API responses in mobile browsers if needed.

Although I tend to agree that a header-based approach is cleaner and more in
the spirit of REST and even HTTP.

------
johnx123-up
Why not Swagger?

