https://github.com/sagotsky/tapir/
I've been playing with a couple APIs at work lately. This is something I really enjoy, with a couple exceptions:
- I don't like working with poorly written libraries.
- When I forgo poorly written libraries, I don't like rewriting the HTTP boilerplate over and over.
I think I've mostly sovled these issues by writing a library that generalizes API interactions. It's called "Tapir," because that was one of the few dictionary words I found with a-p-i in it and I assumed "rapid" was taken.
The basic idea is that I want syntactic sugar that lets me name URLs and then post or get them.
URLs are defined in a json file for each service you'll connect to. Here's an example from my desk.com api:
"case":{
"update":{
"url":"https://{subdomain}.desk.com/api/v2/cases/{id}",
"method":"patch",
"data":["custom_fields"]
}
}
The first line shows that this is the case
section of the API. Desk.com calls its issues cases. I think I've also got a section for users. Their API is pretty intense and I got bored of typing, so I've just been adding definitions as needed on demand.
The next line adds the update method. Cases have all the CRUD methods you'd expect. Update itself is defined in the next three lines:
- The
url
is required. The fragments surrounded by curly braces will be substituted out later. Method
is optional, defaulting to get. Put, patch, post, and delete are also available. I admit I had some trouble with put working with basic auth, so that's using HTTP/Request instead of straight up curl. //@TODO fixmeData
lists the fields that must be post data. I'm not in love with this part of the definition because I think it should be automatic, but I ran into some endpoints that needed some mixed query paramters - ie some in post body, some on the url string - and this was the most straightforward answer.
Okay, so what can we do now that that's defined?
First, instantiate a new Tapir. It takes one argument, which is the service to use.
<?php
$desk = new Tapir('desk');
?>
Use the api
method to select an API, and call
to call one of the URLs (assuming I defined list along with update in the json).
<?php
$desk->api('case')->call('list);
?>
Thanks to PHP's magic __call method, you can use the following shorthand as well.
<?php
$desk->case()->list();
?>
Call takes a second parameter, which is is an associative array of query parameters. By default these will be tacked on to the end of the query. Remember the curly braced fragments in the URL? They'll be substituted out and replaced with items from this array. Items specified as post data will be stripped out here as well and posted.
<?php
$desk->case()->update(array('id' => 123, 'custom_fields' => array('my_custom_field' => 'foobar')));
?>
I thought this would be tricky to get right, but it's been runing in production for months and we've had no trouble with it. It's easy to extend and a joy to work with. I'd like to tweak it a little bit more, but I think this is one of those things that only gets worse the more I delete it with features.