Issue 14: API Design
Spurred by a comment I saw on a Discord server, some thoughts about API versioning, and path-based vs. HTTP-header-based versioning:
Path-based versioning, with URLs such as /v1/users
are pretty common, but this is sometimes done with HTTP headers as well by specifying something like Accept-Version: 1
in the request.
Restify’s Docs (scroll down to “Versioned Routes”) have some good examples of header-based versioning and how to deal with it in your server routes. Restify uses semver-style versions, but I personally prefer a simple single number, with only bumping the version on breaking changes.
That said, almost everyone with public APIs seems to be using path-based versioning.
Header-based versioning makes versions a bit harder to use overall, although less of a big deal if you’re publishing client libraries for your API or if you don’t have any clients outside of your company.
With header-based versioning, you have to decide what to do if the header is missing. Rejecting requests without a version is unfriendly to experiments, but accepting them and just using the latest version can lead to problems later on. Path-based versioning doesn’t have this problem.
Header-based versioning makes it easier to make breaking changes frequently, which is generally bad.
But it can be good sometimes to have that flexibility if your API clients are mostly yourself and you mostly just need to support non-updated versions of mobile apps or unrefreshed web apps.
For yet another versioning strategy, AWS sometimes just publishes “v2” endpoints that sit alongside the original one. (e.g. https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html)
Some other good reading:
- Stripe on API Versioning
- Google- Common Misconceptions About API Versioning
- Google - Which Version of Versioning is Right for You?
I think a big aspect of which to choose hinges on the “REST or RPC” design of your API. If the API is mostly designed for fetching and updating objects, the path-based versioning scheme makes a lot of sense since most breaking changes to the API will affect most of the endpoints, and major changes to the object formats are effectively creating entirely new objects that should be at a different URL from a REST perspective.
If calling an endpoint is more like calling a function that does a bunch of custom work, then the header version can make more sense, or even Amazon’s “add V2 to the end of the name” , as the functions are more likely to change over time in ways that are independent of the overall evolution of the API.
Hope this all makes sense. I just wrote this down over the course of half an hour so please let me know if you disagree somewhere :)
What I’m Working On
I finally published another blogpost this week, on writing middleware for the Actix Web framework. Some of the terminology involved can be a but confusing so I’ve tried to unpack it here.
At work, I finished up a project to move some data-processing utilities from interacting with the local disk to streaming to and from cloud storage. For throughput-limited tasks like this, cloud storage is actually faster than an EBS disk, so this not only saves time in moving the data in and out of cloud storage, but reduces the time that it takes to run overall. Nice win!
Now that the project structure has stabilized on Ergo, I’m currently in the less fun phase, where I catch up on testing and clean up the error reporting structure. Slow and steady progress is the key here, and then back to developing new features again. While this kind of work isn’t the most exciting, it’s nice to get everything in its proper place, to streamline the next phase of development.
If you enjoyed this, I’d love if you share it with a friend (sign up here) or just reply to this email with your thoughts. Thanks for reading!