Building Stripe's API
amberonrails.com
amberonrails.com
One of the things I'm not so sure about is the local bindings for each language. I'm tempted to just use off-the-shelf HTTP clients or a very thin wrapper in each language and write code snippets based on them. I'm not sure I see the value in writing full client bindings - I've often found it harder to use in many cases when I use these 'opinionated' bindings in the past. You often end up with a choice of entirely following the libraries views on error handling or digging around and breaking upgrades by modifying these libraries directly. I've always preferred much thinner wrappers that have no knowledge of the underlying API calls. Would love more opinions!
As an API author, I think your goal should be to make interacting with your API as simple and robust as possible. The downside with just recommending off-the-shelf HTTP clients is that there's always a ton of logic (whether request formatting, error handling, or turning responses into first-class objects) that the vast majority of consumers of your API want and will have to write on their own. If you look at the internals of our bindings, a lot of the logic is around understanding exceptions (https://github.com/stripe/stripe-ruby/blob/master/lib/stripe...) or interstanding semantics of our API (https://github.com/stripe/stripe-ruby/blob/master/lib/stripe...), which are tasks that would take a newcomer a lot of time to get get spun up on.
There will always be frameworks where your bindings don't work (e.g. our Ruby bindings aren't compatible with EventMachine) or paradigms that they violate (e.g. using error return values in PHP rather than throwing exceptions). That's actually ok -- just because you can't support everyone doesn't mean you should support no one. Instead, we put a lot of effort into making our bindings compatible with as broad of a range of environments as possible (e.g. https://github.com/stripe/stripe-python/blob/master/stripe/_...).
So my advice would be write bindings which convert the semantics of your API to the consumer's language, but which constrain the consumer's application as little as they can. Even if people end up having to use a lower-level abstraction to talk to your API, they can probably steal code or ideas from what you've written.
I wrote a lot along similar lines here:
I find that the best engineers (indeed the best people in any role) are the best communicators, who are constantly aware of the many audiences that they are communicating with and are always weighing these many different needs. A good engineer is an ambassador between the technical and non-technical.
Also, who else thought the domain name referred to a new client-side framework for RoR? :)
As someone who was just finished building v1 of a REST API for $work, I wish I had learned some of these lessons 6 months ago. I took a lot of inspiration from Stripe and Twilio but there are so many things I'd do differently for version 2. One advantage I do have is that our API is not consumer facing so I didn't do as much work on the docs and example request/response as I would have otherwise.
My favorite slide was the one showing the details of a particular POST request. I'm not currently logging requests like this, but my eyes have been opened now to the possibilities it brings. Just the ability to debug a response alone would make it worth it. No more tailing apache and backend logs!
I've always wondered how this was implemented:
> We keep a per-user version which reflects the state of the API the first time the user made an API request