sagotsky.github.io

home tags

Tapir

10 Nov 2013 php api tapir

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:

  1. I don't like working with poorly written libraries.
  2. 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:

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.