📂

API client version using headers

Enable multiple responses from the same instance of the API using a simple mechanism.
One typical way to define expectations on an API is to use versioning. While there are several ways to do this—for example, refer to this article from Nordic APIs—we are going to use a header to decide which API backend to actually activate for the request.
​GraphQL is a different beast when it comes to versioning. See this section as REST-specific in its details, but a good idea overall as long as you adapt to what versioning means for your protocol.
🎯 Example: See src/FakeUser/controllers/FakeUserController.ts and note how the header is handled in checkInput().
src/FakeUser/controllers/FakeUserController.ts
/**
* @description Check and validate input.
*/
function checkInput(event: APIGatewayProxyEvent): string {
const clientVersion =
event?.headers["X-Client-Version"] || event?.headers["x-client-version"];
const isClientVersionValid = validateClientVersion(clientVersion || "");
const userId = event?.requestContext?.authorizer?.principalId;
const isUserValid = validateUserId(userId || "");
​
if (!isClientVersionValid || !isUserValid)
throw new Error("Invalid client version or user!");
​
return clientVersion || "";
}
An alternative and perhaps more commonly used approach would be to deploy a new instance of the API—like api.com/v2—but of course, this would create further hardware segregation (having a separate v1 and v2 instance), which we want to avoid.
So, while it may be non-standard, in this context version 2 of the API represents the beta, meaning that version 1 represents the current (or "stable", "old") variant.
With this, we have created a way to dynamically define our response simply through a header, without resorting to separate codebases or separate deployments. No need for anything more complicated, as long as we handle this logic in a well-engineered way.