What it takes to build usable APIs
In February, we launched Coord with a suite of APIs that make it easy to integrate all kinds of mobility services into any application or service. And right away, we learned a lot about what did and didn’t work with our strategy. Even though our APIs now have almost exactly the same capabilities that they did in February, a lot has changed in the interim. Most of these changes were broadly about usability.
Usability can mean a lot of different things. In our case, what we want to do more than anything is have people get useful data out of our system in as short a time as possible. And it turns out that, in order to make this happen, we had to change the whole way we thought about our offering. I wanted to share some of the lessons we learned over the course of this project.
1. Your docs are your product
As a software engineer, it’s tempting to spend all of your time on the core of the system you’re building, which in our case means the APIs themselves. And good API design is important, for sure, but as we started to interact with more and more new and potential customers, we realized that even if our APIs are the core of our system, it’s our API documentation that’s the core of our product.
Many companies view their website as primarily a marketing tool: once somebody signs up for your product, the site has done its job. But if you expect your APIs to add value for your customers, you have to have a site that supports them at every step of the way. For us, this has meant that we’ve had to spend a lot of time understanding and optimizing how developers interact with our site and how our documentation works to be as usable as possible.
You may have read Joel Spolsky, who memorably said, “users can’t read anything, and if they could, they wouldn’t want to.” So why should we spend time on docs that nobody’s going to read? It turns out that while engineers don’t read docs, they do spend a lot of time interacting with examples. Not only do developers (us included!) love to copy and paste source code, seeing a live example is convincing evidence that our API does, in fact, match your use case.
Our Tolls API is a great example. It can be a bit involved to use, because you have to have a way of figuring out the exact path of travel in order to find the tolls that are along that path. So we put together two interactive examples with viewable source code that show exactly how to connect this API together with other services to build a complete user experience.
In fact, over the next few weeks, we’re launching interactive guides for all of our APIs. Having a good reference is necessary, but it’s not going to do nearly as much for your users as showing them exactly how your APIs work in practice. Then, once developers have something that at least works, the API reference will still be there for them to learn more.
2. REST Isn’t Enough
All of our APIs follow the principles of REST. We have resources represented by URIs and use HTTP verbs to statelessly exchange information about them. But, on its own, this is far from enough to make a usable API. As far as the actual design of the API goes, the most important thing is a layer deeper: match the way your API models your services to the way your users do.
For example, we spent a lot of time trying to produce a single API that handled both curbs and off-street parking. We expected our users to think of these the same way: after all, they’re both just pieces of pavement you can put cars on, right? But it turns out that, in practice, what people want from these pieces of pavement are very different. For off-street parking, the challenges are around things like opening hours and access methods. But for on-street parking, it’s much more important to accurately model the whole set of different things you can do on the side of a street, like picking up passengers, loading or unloading goods, or parking for an extended time. So we had to split these APIs into two to better match what our customers were trying to get done.
REST is a helpful tool for making APIs behave as users expect, but there are at least as many bad RESTful APIs as there are good ones. The thing that sets the good ones apart is a developer-centric viewpoint.
3. Errors Matter
It’s easy to neglect error messages. After all, our APIs are so easy to use that nobody should ever get an error, right? But, remember: nobody reads docs. This means that most of your developers will end up learning your APIs by trial and error. And trial and error only works if the errors teach you something.
Our authentication experience is the best example of this. We’re really excited about how we use open standards like JWTs to easily let users transact through our APIs without having to log into Coord (more on this in a future blog post!). But because they’re so central to security, JWTs can be a bit finicky to work with. When we get a JWT that we can’t accept, it would be easy for us to just send back a message saying, “invalid JWT”. But we know from personal experience that this kind of error message leads to particularly infuriating debugging journeys. So we’ve made sure that our API returns detailed and specific error messages that don’t just say exactly what went wrong in the request, but how to fix it.
Ultimately, APIs never stop changing, because the world never stops changing. As the use cases that an API supports continue to evolve, it will evolve too. And the mobility market is evolving faster than almost any other part of the economy right now, so we’re sure that our APIs have a long way to grow in the future. We’d love to hear from you about your experience using our APIs, and the use cases that you’d like us to support, so we can do our part to make it easier for people to get around cities.