Versioning
Versioning APIs using request headers

Versioning APIs using request headers

Enable versioning on a per-request basis.

Verion headers allow API consumers to specify the desired API version for each request.

Using headers to define version numbers is more RESTful since multiple versions of the same resource are addressed by the same URI. By distinguishing between the concepts of the resource, which as a fixed identity, and the resource's representation, links to resources are preserved over time and can be used as permalinks.

An example of a request might look like:

curl https://api.example.com/items/123 \
  -H 'ExampleAPI-Version: 2012-10-27'

Option 1: Use a custom header

There is no standard HTTP header field that defines the version of a resource's representation, meaning APIs need to define their own. The table below descibes some common options.

Header nameNotes
Accept-VersionAligns with existing content-negotiation headers, such as Accept-Language and Accept-Encoding.
ExampleAPI-VersionClarifies that the header is specific to the API vendor.

Option 2: Use HTTP content negotiation

HTTP content negotiation allows the client (user agent) to describe what kinds of representations of the it can handle. This mechanism is typically used to request specific content types such as text/html, but can easily be extended to describe the version of the representation. The server responds with the requested representation if it is able to, or otherwise responds with an appropriate error.

Content negotiation primarily uses the Accept request header. This can be extended to include the version number like so:

Accept: application/vnd.example.v1+json

Or, alternatively using Accept extension parameters:

Accept: application/vnd.example+json;version=1.0

If the request is successful, the server's response will contain the Content-Type header, which describes the specific representation that was negotiated:

HTTP/1.1 200 OK
Content-Type: application/vnd.example.v1+json

In some cases, the server may respond with a different version to that which was requested. For example, if there is a more up-to-date version that is backwards compatible to the requested version.

When using the Accept header as part of content-negotiation, the appropriate status code for unsupported versions is 406 Not Acceptable.

Pros

  • Follows REST principles that multiple versions of a resource are still identified by a single URI.
  • Content negotiation allows the server to respond with a more up-to-date version than requested, if still backwards compatible.
  • The Accept header allows for multiple representation versions to be included in the same OpenAPI definition.

Cons

  • Developers may easily omit the header if it is optional, potentially leading to surprising behaviour when a new default version is released.
  • The API is more difficult to consume, particularly if extending the Accept header.
  • The server implementation may be more complex as versioning cannot be implemented at the gateway or router layer.

Usage

To set the API version on a specific request, send an ExampleAPI-Version header:

curl https://api.example.com/records \
  -H 'ExampleCo-Version: 2.1.7'

Requests without the ExampleAPI-Version header will default to use the latest version.

If you specify an API version that is no longer supported, you will receive a 400 error.

Implementation notes

Resource URIs that can responds with different representation versions of the resource should always include the Vary header in responses. This instructs any caches that differently versioned responses should be cached separately.

The Vary header is formatted as a comma-separated list of header names that influenced the response. For example, if using a custom header:

HTTP/1.1 200 OK
Content-Type: application/vnd.example.v1+json
Vary: Accept, Accept-Encoding, ExampleAPI-Version

{
  "data": [
    {},
    {}
  ]
}

OpenAPI reference

This OpenAPI document descibes an API that is versioned using a custom request header, with the version number formatted using Semantic Versioning.

{
  "openapi": "3.1.0",
  "info": {
    "title": "Header Versioning API",
    "version": "2.1.7"
  },
  "paths": {
    "/items/{item}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/ExampleAPIVersion"
        }
      ],
      "get": {
        "summary": "The item",
        "parameters": [
          {
            "$ref": "#/components/parameters/ExampleAPIVersion"
          }
        ]
      }
    }
  },
  "components": {
    "parameters": {
      "ItemID": {
        "name": "item",
        "in": "path",
        "description": "The unique ID of the item.",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "ExampleAPIVersion": {
        "name": "ExampleAPI-Version",
        "in": "header",
        "description": "Set the API version on a specific request. If not specified, the default value is the latest API version, currently `2.1.7`.",
        "required": false,
        "schema": {
          "type": "string",
          "pattern": "^([0-9]+).([0-9]+).([0-9]+)$",
          "default": "2.1.7"
        }
      }
    }
  }
}

Alternative design patterns

URI versioning

Clearly segment different versions of the API.

Read more

Was this page helpful?

Made by Criteria.