3 ms·
Nice to see the way it's 'supposed' to be done, but really that's a lot more complicated than it needs to be. Most APIs can get away with "HTTP requests that
by jasonkester 17y ago
Nice to see the way it's 'supposed' to be done, but really that's a lot more complicated than it needs to be. Most APIs can get away with "HTTP requests that do stuff".
As an example, here's how you create a new meeting with Twiddla's (evidently RESTless API). One POST over SSL:
> POST https://www.twiddla.com/new.aspx
> username=billy
password=iLikeRainbows
< HTTPS/1.1 200 OK
< 109232
Now, here's how this author suggests people do it:
> GET http://api.twiddla.com/
< [XML packet full of endpoints comes back]
> GET [endpoint you parsed from that list]
< HTTP/1.1 401 Authorization Required
> GET [same endpoint after jumping thru crypto hoops]
< HTTP/1.1 200 OK
< 109232
As an API publisher, I can see absolutely no value in making my users jump through all those hoops just to use my API. The API exists so that people can get things accomplished on my site, and I don't see any reason why it shouldn't be just as usable as the site itself.
Please, if you're putting out a simple API, don't make it overly complicated just to please this author and others like him. Make it exactly as complicated as it needs to be to perform the task intended and no more.
- Andys 17y agoWell he's just spelling out the steps to explain HTTP Digest. In the real world, any HTTP client library worth using already implements HTTP authentication transparently to you, the API consumer.
- jasonkester 17y agoThat's actually surprising, that the default behavior for a HttpWebRequest.GetResponse() method would be to parse the response and decide to send off a second request automatically. I would expect some developer involvement would be required. Regardless, assuming I'm using your library, I'd still need to do a request, some XML parsing to discover the right url, followed by a second request, just to get back the response I want. Compared to 1 request, that's still 3 times the effort for no added benefit.
- DougBTX 17y agoIt's an interesting artefact of the libraries we use that digest authentication is difficult, but you can "just use" SSL.
- psadauskas 17y agoThey make digest easy, too: curl --anyayth --user admin:sekret http://exmaple.com/resource_protected_by_digest_auth
- kragen 17y agoMost libraries I've used have the option to respond to 401s automatically, and a lot of them have HTML parsing, too. There are some added benefits. The load-balancing example he gives in the article is one; a second one is that there's less stuff to get wrong in the client code, generally. Instead of working from some informal equivalent of WSDL, you're writing code that interrogates the service at run-time to find the current definition of the interface.
- jamie_ca 17y agoIf more people did proper restful applications, perhaps there would also be proper libraries for interacting with them? Perhaps something that looks like this (with a ruby flavor): RestfulApi.new('http://api.twiddla.com/ http://api.twiddla.com/, :user => 'billy', :password => 'ILikeRainbows').post('Meetings')
- psadauskas 17y agoYes, exactly. I've written a (rough) DataMapper adapter for interfacing with them. class User include DataMapper::Resource resource_name "AllUsers" # define some properties end User.first(:login => "admin") http://github.com/absperf/dm-ssbe-adapter/tree http://github.com/absperf/dm-ssbe-adapter/tree
- jimbokun 17y ago"< [XML packet full of endpoints comes back]" I'm going back and forth on this one. On the one hand, it is a pain to go through those steps if you already know which service you want. On the other hand, having that listing available makes the site kind of self documenting, in that you can explore the services available. What I find more potentially useful is the idea of putting URLs into the XML for subordinate resources instead of some kind of ids or other identifiers. Then the client can follow those URLs to get a user's documents, or whatever it is you are modeling. Anything where there is a relationship but it is too expensive to just dump all the data in a single XML response. It's pretty intuitive, and arguably easier than just supplying an id that the client must use to construct the appropriate URL.
- psadauskas 17y agoOnce you write a client, and its pretty simple, you don't have to worry about that step at all. And since the initial document rarely changes, and it can be cached, you usually only have to get it once. Here's some code in ruby that uses a service like this to find a user by their login: def find_user(login) users.select { |u| u["login"] == login }.first end def users users_href = services.select { |s| s["name"] == "AllUsers" }.first["resource_href"] JSON.parse( @http.resource(users_href).get(:accept => SSJ).body )["items"] end def services JSON.parse( @http.resource(@services_uri).get(:accept => SSJ).body )["items"] end @http is a handle to an HTTP library, and @services_uri is the well-known URI. So its not nearly as complicated as it might seem at first, and the benefits are tremendous.
- psadauskas 17y agoYou're combining two issues. HTTP Digest requires the initial 401 unauthorized, but the same number of requests after that (And curl/libcurl handle it all for you, you don't need to think about it). I was just attempting to show what was going on, and why it was more secure than an API token. You're example requires that every API call use SSL, which means noone is allowed to cache it, which is going to be a hinderance on the scalability of you API (not impossible, though, but you're going to have to come up with your own, rather that just throwing squid in the middle). The other part is discovering of the service locations. By not doing so, you're handcuffing yourself. In your API, you are stuck forever with `/new.aspx`. Should you decide someday to have something else you want clients to be able to create, you can't separate it out into `/new_foo.aspx` and `/new_bar.aspx`. Doing these kinds of things actually make it less complicated in the long run, just like using jquery is less complicated than copy/pasting 50 lines of javascript of the web.
- jasonkester 17y agoHmm. You seem to have rebutted my argument by retyping your article. The API in question has exactly one endpoint, so no possible value could come from having to look it up on a list each time you want it. And it is a POST to create something, which means you'd never cache it. I picked that example because it is an existing use case that demonstrates that the rules you're proposing don't apply to every situation.
- psadauskas 17y agoI must have missed the part where you said the API would only have one endpoint, ever. Roy's thoughts on the constraint is that there is only one well-known entry point, and my article was a little more lenient with "very few". Each one, however, is an additional maintenance burden on both the app writer and a client writer. If your app only has a single resource, then there's no reason why it can't be the one well-known resource itself. There's no need to be snarky, these constraints apply perfectly to your application as it is. If you have any intentions of your app growing beyond that single resource, however, its not that complicated to add these constraints to make that future growth easier.