This week, we are excited to share with you the alpha launch of our Public API, but what exactly goes into designing, implementing and documenting an API? What APIs do you even build?
Start with Customer Need
Before the what, we must ask the why. When customers ask if we have an API, why do they want one, what is their use case? It is all well and good investing the time to build an API for our customers, but if it doesn’t solve their problem or provide them value, then that investment is wasted.
We could just replicate the functionality of our existing application in the form of an API, but is that valuable?
We’re lucky to have such a close relationship with our customers, holding very regular feedback sessions. A common theme we extracted was an interest in seeing their supplier information inside their internal tooling, this may be a data warehouse or even a slack bot. That’s it, we have our first API endpoint.
Outline your Core Principles
Do we build a REST API, or an RPC API? What about GraphQL? What encoding should we use, JSON, Protobuf, XML? How do we version or implement breaking changes? What error information is useful?
When there are a lot of questions to answer, I tend to reach for prior art. What APIs have we worked with as a team, that we enjoyed working with and feel are particularly well designed, and why did they come to those design conclusions?
Commonly cited during our design process, were the Stripe API and the Google API Design Guide, which gave us a good feel for how we should be thinking about these problems, and gave us inspiration for what to build.
We settled on a REST-ish resource hierarchy encoded using JSON, as this provides a nicer developer experience in our opinion. Although it is worth noting, we have required the HTTP Accept and Content-Type headers for all requests, should we want to support other encodings in future (we use Protobuf internally).
Similarly, we settled on including versioning in the URL, as this is a pattern we feel most developers would be familiar with. We did consider a dedicated versioning header, or even versioned Content-Type values, and we might come back to those ideas in the future.
We also particularly like error handling as a first class citizen, a feature so often an afterthought in API design, and have thus made it part of the specification proper.
Security First Mindset
We’re a cyber security company, our security is at the forefront of everything we do, not just in our API. We paid careful attention to the authentication and auditability of our API at every stage of the code review process, and will be a focal point of our next penetration test.
Automate the Heavy Lifting
We identified early on that boilerplate could be burdensome, so we decided to make heavy use of code generation.
Our backend is entirely written in Go, and thankfully, there are a number of tools to support API development available. We quickly spun up a number of proof-of-concepts trialing these tools, something we regularly support as part of our ordinary development process, and eventually settled on go-swagger.
With go-swagger, we can annotate our backend code in such a way as to generate an OpenAPI compatible specification, and vice versa. We can subsequently use this to generate a server interface to implement against, generate client libraries in a variety of languages for customers to get started with quickly, and crucially generate meaningful documentation; all from a single definition.
We additionally considered grpc-gateway. We already use gRPC to define our backend microservices, so it seemed the logical conclusion, allowing us to continue using our existing patterns and infrastructure. However, it’s infrequent maintenance history, coupled with lacking support for newer OpenAPI versions, we chose to evaluate it again at a later date.
Solicit Feedback, Iterate Quickly
Going back to the Customer Need, we’ve built our first endpoint, but does that actually solve their problem?
The benefit of working closely with a select few customers who expressed early interest in a Public API, is a quick and thoughtful feedback loop.
We accept we are not going to build the perfect API from day one, but a good feedback loop means quick iteration is possible. And by outlining our core principles early, we have a reference to keep ourselves aligned.
But overall, we are happy with what we’ve built, and we hope our customers are too. We hope to keep adding endpoints as the need becomes clearer and we receive more feedback.