5 ms·
How to Write a Self-Documenting API - Heyzap API release
- hinathan 15y agoI 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-format-my-json-output-in-ruby-on-rails http://stackoverflow.com/questions/86653/how-can-i-pretty-fo...
- cicloid 15y agoMaybe 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 15y agoNot 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/ 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 15y agoYou 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
- immad 15y agoHadn't thought of that. Done. I may revise if it increases server load significantly but it looks good for now: http://www.heyzap.com/api/v1/activity/android http://www.heyzap.com/api/v1/activity/android
- cellularmitosis 15y agoPerhaps this would be a good place to tie into the "Accept:" request header? If it says text/html in Accept:, you're still going to return JSON, but you can use this as a hint that it is probably being read by a human, and you can pretty print it. But if you see application/json in Accept:, then you assume it's an API call from a phone or script and you minify it instead. Edit: however, that requires cooperation from others, so is prone to failure. Perhaps also take hints from the user agent string? Edit 2: drat, someone already beat me to this suggestion. However, I'll use this as an excuse to pimp my last weekend hack: adding an Accept: decorator to itty.py http://news.ycombinator.com/item?id=3665743 http://news.ycombinator.com/item?id=3665743
- waffle_ss 15y agoWhen 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-understands-rest-or-http#i_want_my_api_to_be_versioned http://blog.steveklabnik.com/posts/2011-07-03-nobody-underst...
- immad 15y agoHey, 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 15y agoAccept header based versioning is self-documenting. I've worked on implementing support for this in tastypie: https://github.com/toastdriven/django-tastypie/pull/394 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 15y agoWithout reading the docs at quite depth I think it would be easy to overlook the response content-type
- bmelton 15y agoThat's also a pretty recent pull, and wasn't there the last time I saw Klabnik's post here on HN (a couple weeks ago).
- philipn 15y agoWell, I think the way you do it is provide examples of interaction that sends an explicit Accept with client interactions. Detecting Content-type and reacting accordingly is only for totally blind discovery.
- slewis 15y agoFor 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/ 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/ http://django-rest-framework.org/
- bmelton 15y agoHow 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 15y agoIt 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 15y agoCan 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 15y agoWhen 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/examples/pygments.html http://django-rest-framework.readthedocs.org/en/latest/examp... And also, from the Tastypie docs: http://django-tastypie.readthedocs.org/en/latest/resources.html#why-resource-vs-modelresource http://django-tastypie.readthedocs.org/en/latest/resources.h...
- einhverfr 15y agoThey 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-soda.html http://ledgersmbdev.blogspot.com/2011/10/introduction-to-sod... for more info). Anywhere there is a connection between software, this can be a good approach. Why limit it to the web?
- deleted 15y ago[deleted]
- johnx123-up 15y agoWhy not Swagger?