A short presentation on how you might like to build a simple "Web API".
Updated: an accessible version with errata fixes and links:
- A Web Friendly API?
- Javascript AJAX Python Ruby PHP Perl Curl
- [Picture: collection of Web 2.0 logos from flickr, Google, Yahoo!, last.fm, etc]
- One thing in common ..
- They HATE SOAP
- But LOVE The Web
- URIs identify stuff
- And can be anywhere
- [photo of shower head with URI WWW.SPEAKERMAN.COM]
- Use cool URIs
- Read RFC 2616
- Constrain Verbs: GET/HEAD and POST (PUT, DELETE, OPTIONS - YAGNI?)
- Ask "IS IT SAFE?" [photo of the dentist from Marathon Man]
- Understand HTTP Methods:
method safe idempotent semantics resource cacheable ----------------------------------------------------------- GET | X X X X X | HEAD | X X X X X | PUT | X X X | POST | * | DELETE | X X X | OPTIONS | X X X | ----------------------------------------------------------- PROPFIND | X X X X * | PROPPATCH | X X X | MKCOL | * X X | COPY | X X X | MOVE | ? X X | LOCK | X X | UNLOCK | X X X | PATCH | * X X | ----------------------------------------------------------- - think about representations: HTML, RSS/Atom, XML, JSON, whatever
- Warning! You are about to see Naked Protocol Headers!
- Content-Negotiation:
HTTP GET ... Accept: application/weatherml+xml; q=1.0, application/xml; q=0.8, text/html; q=0.5Apache Server .htaccess AddType application/weatherml+xml wea Options +MultiViews ./index.wea ./index.xml ./index.html - enjoy the free caching
HTTP GET http://flickr.com/photos/psd/2450160 If-Modified-Since: Fri, 31 Dec 1999 23:59:59 GMT If-None-Match: 'guid-21343244324'
HTTP/1.1 304 Not Modified
- make Phone Call
HTTP POST http://example.com/calls Content-Type: application/x-www-form-urlencoded Accept: text/xml; charset=utf-8 callingParty=tel:+447918808 calledParty=sip:Merlin => HTTP 1.1 201 Created Location: http://example.com/calls/123213 Content-Type: text/xml; charset=utf-8 <callInfo> <callId>http://example.com/calls/123213</callId> <callStatus>Initial</callStatus> </callInfo>
- get Call Info
HTTP GET http://example.com/calls/123213 Accept: text/xml => 200 OK Content-Type: text/xml; charset=utf-8 <callInfo> <callId> http://example.com/user/fred/calls/123213 <callStatus> CallInitial <callingParty> tel:+447918880... <calledParty> tel:+447918880... <timeStarted> 2007-01-09 11:45:20 <duration> 502 <terminationStatus> CallNotTerminated </callInfo>
- end Call
HTTP POST http://example.com/calls/123213 Content-Type: application/x-www-form-urlencoded callStatus=Terminated => 202 Accepted Location: http://example.com/calls/123213
- list Recent Calls [Feed Icon]
HTTP GET http://example.com/calls/feed => 200 OK Content-Type: application/atom+xml <feed xmlns="http://www.w3.org/2005/Atom"> <title>Phone Calls <link rel="self" href="http://example.com/calls/" rel="alternate" type="text/html"/> <updated>2007-01-0911:45:02Z <author><name>Phonebox <id>tag:example.com,2007-01-09:/calls <entry> <link href="http://example.com/user/psd/calls/1234567/"/> <title>Call 1234567 <id>tag:example.com/calls/1234567-200701091223313 <summary>CallInformation <updated>2005-10-13T18:30:02Z </entry> <entry> <link href="http://example.com/user/fred/calls/17231667/" ... - Overall:
http://example.com/calls http://example.com/calls/feed http://example.com/user/paul/calls/feed http://example.com/user/paul/calls/7d6374da5 http://example.com/user/paul/calls/search?callingParty=tel:%3A44791888 http://example.com/sms http://example.com/sms/feed http://example.com/user/fred/sms/7d6374da5 http://example.com/user/fred/sms/inbox/feed http://example.com/user/fred/sms/inbox/7d6374da5 http://example.com/user/fred/sms/inbox/search?from=tel:%3A44791888 ....
- Yes, Dear Reader, there's no API as such it's just yet another Web site ..
- Surf long and prosper!


Great stuff !
Nice! I'd hang up the call with DELETE on the URI though, or failing that use PUT of "status=terminate" because you're trying to set the state of the call.
Dang! I was planning a blog post along the lines of your shower head photograph. Great presentation though.
This is pretty cool. Of course, like all cool things (the Fonz, say) it's not quite true (he was just an actor. Really).
Here's a web api that isn't a website:
http://dev.aol.com/aol_video/index.html
I'm being facetious. We can all come up with a long list of terrible web apis. What worries me is the move away from WS-* to so called "web apis" that aren't at all RESTfull. The AOL example is just an example, in fact quite badly designed APIs are quite prevalent.
What really, really worries me is that we'll end up with a huge number of variable quality APIs. Many from the same providers.
Flikr API v 34.7 anyone?
Wel said sir!
Sean
Nice stuff!
On slide 18 the response should return a 304 Not Modified rather than a 412 Precondition Failed. IIRC using the 'If-Unmodified-Since' or 'If-Match' will return a 412.
Paul.
I hate to ask a stupid question, but I've seen that query-URI style various places over the years, but I can't recall whether there's a hard spec/name for it. Could you help?
Thanks Everyone for the kind comments!
Mark: DELETE would remove the call record and PUT (AIUI) would require a resource for just the callStatus. I'm also challenged because that rules out J2ME, many browsers and people behind stupid proxies. As it happens, this POST is idempotent, so PUT doesn't add much value here.
Pete: I'd be honoured if you used the showerhead (I'm tempted to turn it into a "URIs Everywhere" icon)
Nic: I too see little benefit in APIs which just use POST - a pox on all your POXes! I should have said "The *Best* Web APIs are Just Web Sites". I also deliberately avoided the R-word given that would have turned my audience off from the word go.
Paul: Gah, so much for the server I tested that with! I'll fix it in a web friendly version of the presentation.
Bill: The query-URIs are straight out of RFC2396. Having the imperative "search" in a URI isn't very RESTian, so it's a noun I tell you!
I guess the query string could be a matrix style URI, but the benefit is you can write a GET form in HTML without any Javascript in the browser.
Yes! Web Service = Web Application
The difference is only in the representation.
Very interesting demo indeed on the use of REST
Mark pointed an interesting question on the usage of PUT and you answered :
"PUT (AIUI) would require a resource for just the callStatus"
I don't understand that. Why this should not have the right to be a Resource and should stay a meaningless string ?
Second, a question to the great REST community on this blog : did not we move the complexity from HTTP to the understanding of XML schema such as weatherxml ?
My idea would be to find a way to interpretate XML as a batch format for HTTP GET.
Doing GET /call/1111 and receiving
On
should be equivalent to doing GET /call/1111/status and receiving the text "On".
What you (collectively) do you think about that ?
In the "overview" bit, your last URL contains:
/inbox?search?from...
But, did you really mean this:
/inbox/search?from=...
[...] Paul Downey » Blog Archive » Web APIs Are Just Web Sites (tags: api REST web) [...]
I see, you're just treating some of the context of a message as its path, rather than as attributes to put in the query section of the URI.
Does this model let you search across users, e.g.
/calls/search?callingParty=tel:%3A44791888
instead of
/user/paul/calls/search?callingParty=tel:%3A44791888
And what would the URI look like for a *feed* of those search results?
Great questions, Bill!
You could do away with the "feed" and "search" legs and use content-negotiation and query parameters respectively to trigger either "actions", i.e.:
/user/paul/calls/feed/search?callingParty=tel:%3A44791888
or
/user/paul/calls/feed?callingParty=tel:%3A44791888
or just
/user/paul/calls?callingParty=tel:%3A44791888
and use content-negotiation to ask for Atom..
I notice flickr and other Yahoo! services often have a format=atom, format=json option for query_strings, and I can see advantages in that, but it's really no better than having a .html, .xml, .atom suffix, something I've avoided as a point of style.
Searching across users would be fine, but which calls you would see would have to depend upon authorization - Twitter and Flickr have a notion of things being "public", "friends", "family" or private to just you.
Great presentation! I love the "Is it safe" quote :-)
Link Love...
Just in case these went unnoticed:
Duncan Cragg has put up part 3 of “The REST Dialogues.” I can’t say I’m in 100% agreement with Duncan. In fact, I have difficulty with the same things that “ocean” over at discip...
[...] Web APIs Are Just Web Sites (tags: rest API web HTTP architecture by:paul_downey) [...]
"http://www.innoq.com/blog/st/ Says:
January 14th, 2007 at 9:03 pm
Great presentation! I love the “Is it safe” quote :-)"
I has visited. :)
To all I advise
[...] Pretty URL’s and uniform controller methods barely scratch the surface of the benefits imparted by REST. Consider the potential use of a generic HTTP interface as a simple web API. The prospect of being unencumbered by the complexity of SOAP opens the doors for use with AJAX and in simple scripts. Fielding’s dissertation goes on to describe the caching and scaling benefits of a pure REST architecture. Tags:REST, ruby, ruby on railsShare and Enjoy:These icons link to social bookmarking sites where readers can share and discover new web pages. [...]
[...] Original post by paul.downey and plugin by Elliott Back [...]
[...] Paul Downey on “Web APIs” April 21st, 2007 — danbri Via Danny Ayers via planetrdf, a very nice presentation from Paul, on the simple but massively under-appreciated theme: Web APIs Are Just Web Sites. [...]
The UI Case for REST...
Yesterday, I did another one of those “REST — the better Web services model” talks, which are becoming routine, but still make me think each time I do them. This time, I actually illustrated a number of concepts by using curl to acces...
Thanks for the great post! I really liked the quote "Is it safe"...Keep it up
[...] Dare Obasanjo draws a distinction between information exposed on the service’s web pages and that exposed through the API. While the quality of the data may differ significantly, I’d suggest that in terms of licensing this distinction is bogus. If I can copy & paste from one app to another, that can have the net end result as scraping. As Paul Downey put it, good web APIs are just web sites. [...]
original DataPortability workgroup vision.TF...
The advocacy of existing open standards has been a core purpose of the original DataPortability workgroup. as evidence in numerous discussions. >...
[...] admit to my shame, than it wan’t until I started reading some of Paul’s stuff on Web APIs that I even realised what URIs [...]
[...] promote is this idea that good websites are APIs. Tom mentioned Paul Downey’s notion that Web APIs Are Just Web Sites. It’s a subtle but extremely important point that I learned primarily working closely with [...]
"Naked Protocol Headers" Don't you just love 'em. Great Heading.