0

New to writing REST APIs. Had a question about versioning.

Let's say that we have a service with the following methods:

  1. Search <- Given some data, it will perform a search
  2. Billing <- Given a time-range, it will provide usage information on the Search API.
  3. EnhanceIndex <- Client can send data to increase the search index.

Let's say that I now decide to only update the "Search" API. What REST versioning format would make sense?

Should I do

  • example.com/search/v2/...
  • example.com/billing/v1/... <- Still provides data from the v2 api
  • example.com/enhance_index/v1/... <- Still influences searches in v2 api

or

  • example.com/v2/search/...
  • example.com/v1/billing/... <- Still provides data from the v2 api
  • example.com/v1/enhance_index/... <- Still influences searches in v2 api

or

  • example.com/v2/search/...
  • example.com/v2/billing/... <- Same API as V1.
  • example.com/v2/enhance_index/... <- Same API as V1

Or something else? Also, is it a bad practice if I don't update all the endpoints in one-go (even if there is no diff), and have some V1 endpoints around that are affected by V2 usages (and vice-versa)?

I've also read a bit about putting the versioning in the mime type, however I don't think that really addresses the question above, it just seems like a non-URI version of the same thing (but correct me if I'm wrong). In general, should I still consider Header-based versioning anyway? (I noticed that a lot of public APIs still put it in the URI)

Thanks!

1 Answer 1

2

As always, let's start with there are 2 kinds of REST out there.

REST ~ RPC: This is what most projects mean, where REST means JSON over HTTP, endpoints are services to be called. Not different from RPC, SOAP, or technologies that came before.

In this scenario versioning is usually in the path, as you proposed. Because the clients are essentially hard-coded to calls and specific formats, through opanapi/swagger or some other generator-based thing, the server can not change these anyway. Also, there is no hypermedia, i.e. relations between endpoints. It is all, again, hardcoded in the clients. This all essentially means URIs don't mean anything, you can have them anyway you like, even mix versions. Clients will always need to be updated anyway.

REST as it was originally described: Here URIs mean something. For example the Bill, Product or even the Search. These are called "resources". If I have a URI to a Product, that URI will stay the same essentially forever. It will not be modified with software versions, or even when the representation changes.

In other words, bookmarks will always work, same as if you bookmarked things on the internet, you would want that URI to work even years from now, even if the design or format changed. As you can probably see, having software versions in URIs destroys this property immediately.

This is why "media types" are a thing. Media types describe the technical representation of a thing. It is still the same thing, only described differently. This is why, if you are doing this kind of REST, you'll probably want versions in the media type, if you want versioning at all.

What you get is that you can update things without necessarily breaking clients. The server is free to modify its resources, free to define different workflows, etc.

This requires a whole different approach though, including using hypermedia instead of hardcoding everything into the client.

Summary: Depends on what you want. If you're fine with hardcoding the client (for example its under your control), RPC-style is fine. Versions in the path are fine, even mixed or however you want it. If the client is not necessarily under your control and you want the flexibility to update things on the server, including workflows, you'll probably better off with the original REST.

1
  • Thank you. For our use case, we have a mix of both. Primarily the service forwards to gRPC under the hood, however the clients aren't in our control. I didn't quite understand this - "What you get is that you can update things without necessarily breaking clients.", we won't break the client from the URI level, but we will affect them in the mime-versioning level, right? So we'd need to support old version types while we migrate. Also, do you have any opinions on the "is it a bad practice if I don't update all the endpoints in one-go (even if there is no diff), ... ?" question?
    – de1337ed
    Jan 28, 2022 at 18:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.