0

Is there a standard or convention on whether location retuned by a REST server should also include the version information? Per REST, the URI is to a resource so by that definition, the URI returned in the Location header should not have a version.

But a GET on the location returned by the server is supposed to work, but it fails if version information is not added to the URI. Is the client supposed to know the preferred version of the server, especially when there may be API gateways that aggregate multiple backend microservices that are on different API versions?

Is there a standard on this, should or shouldn't the server return the API version in the response?

Superman
  • 221
  • 2
  • 11
Xavier John
  • 8,474
  • 3
  • 37
  • 51

2 Answers2

1

There is no standard when it comes to versioning and REST. REST is a system of constraints. There are, however, methods of versioning that adhere to the constraints and those that do not (such as in the URL path).

An API version should not be thought of in the same way as a version for binaries. While "API version" is a widely accepted term, it's a bit of a misnomer. An API version doesn't indicate which method to call for an API, it indicates the format. Remember that HTTP is the API. HTTP does not have method overloads or versions. What's behind that is an implementation detail.

This means that a media type best describes and serves the purpose of an API version, even if there are other ways to convey it. The server's job is to tell you where a resource is located via Location when you create a resource with a server-generated identifier. It is not obligated to tell you what format you (the client) want it in. Since you just created a resource specifying a specific API version (or format), you should know how to send a GET to retrieve that resource.

The same rules and logic apply for HATEOAS. If the server provides the location of related resources, it cannot know what API version (or format) of those resources that you - the client - want. The independent evolution of services often results in heterogenous versions across APIs.

Exactly how these concepts can be applied to microservices is a bit off-topic, but it is entirely possible that one service writes a resource in a v1 format, while another service reads the resource in a v2 or v3 format. Regardless, the Location of the resource should be the same and is shareable across service boundaries.

Chris Martinez
  • 3,185
  • 12
  • 28
0

Per REST, the URI is to a resource so by that definition, the URI returned in the Location header should not have a version.

That doesn't quite follow.

a URI is a resource identifier; it identifies a resource, where "any information that can be named can be a resource (Fielding, 2000).

In general, the representation of a resource is a function of time; and a response to a GET request is expected to return the latest version of that resource.

But, if that's not suitable, then it is fine to instead model a different resource that has a representation which is not a function of time.

/705604c9-2e1f-43c8-953e-7659f44f5b32 <-- "version 0"
/bbd02ea3-96d8-41dd-ac70-4748bd3e93ac <-- "version 1"
/86d09182-5002-4568-8a4a-352a75daa40c <-- "version 2"
/32a856ef-4894-49f4-8e27-ab3ab41de71f <-- "latest"

Of course, these identifiers are not particularly helpful to a human trying to recognize them, so you'd probably want to use a friendlier spelling convention

/foo/history/0
/foo/history/1
/foo/history/2
/foo

For API versions, your humans will probably be happier with different prioritization of the path segments

/api/v0/foo
/api/v1/foo
/api/v2/foo
/api/foo

In contexts where backwards compatibility is important, you want to be really careful about changing the meaning of a resource.

In cases where the meanings are constant, but the representations are changing over time, then you might use content negotiation (either pro-active or reactive) to help clients to retrieve a representation with the right schema. So if someone tries to GET the resource, but doesn't describe one of your supported schema in the Content-Type header, then maybe you send them an 300 Multiple Choices response, and go from there.

(At this point, we're starting to enter the realm of bespoke clients, which is a bit outside the scope of REST, which itself focuses on general purpose components.)

VoiceOfUnreason
  • 52,766
  • 5
  • 49
  • 91
  • I mostly agree with your expanded explanation. `/foo/history/{n}` is a good example of the looseness in the meaning of the term _"version"_. In that context, _version_ might enter the vernacular, but each _version_ (or snapshot) is likely to be a distinctly different resource. This is not true for `api/v1/foo`. This happens all-too-often. `v1/orders/123` and `v2/orders/123` are almost certainly not different resources, they are different _representations_. Despite being a very popular versioning method, this is a violation of the _Uniform Interface_ constraint IMHO. – Chris Martinez Jan 19 '22 at 20:19
  • @ChrisMartinez versioning resources, regardless if v1, v2 or some /foo/history/n pattern is used, is just an indication that you actually are attempting to map a RPC like design into a REST pattern. REST is meant for evolving resources and changes done to a resource will immediately progress to clients which are designed to coop with those changes. If you want to express something like a version history in resources you can basically mimic GIT commits with the available HTTP toolset, i.e PUT may have sideeffects which creates a commit resource additionally to the changes on the "head" resource – Roman Vottner Jan 19 '22 at 22:53
  • @RomanVottner I can totally see that and even get onboard with it. I wouldn't design an API like that. I didn't want to split hairs over it, but it's not necessarily in violation of a constraint, even if we agree that's not the way we'd model it. Similarly, I feel that @VoiceOfUnreason pointed out that segments divided by `/` are purely for human readability. It does **not** convey any hierarchy, division, or organization, despite popular belief. – Chris Martinez Jan 20 '22 at 00:58