Version API by Accept Header with Vendor Media Types in Python

Build a mock HTTP server that routes to API versions by parsing vendor-specific Accept headers in Python.

Medium Python 3.9+ Aug 9, 2026 API design & gRPC 13 views 0 copies

Python code

40 lines
Python 3.9+
from http.client import HTTPMessage
from http.server import BaseHTTPRequestHandler, HTTPServer


class VendorVersionHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        accept = self.headers.get("Accept", "")
        version = "v1"
        if "application/vnd.myapi.v2+json" in accept:
            version = "v2"
        elif "application/vnd.myapi.v3+json" in accept:
            version = "v3"

        body = f'{{"version": "{version}"}}'.encode()
        self.send_response(200)
        self.send_header("Content-Type", "application/json")
        self.send_header("Content-Length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)

    def log_message(self, format, *args):
        pass


def parse_accept(accept_header):
    if "application/vnd.myapi.v3+json" in accept_header:
        return "v3"
    if "application/vnd.myapi.v2+json" in accept_header:
        return "v2"
    return "v1"


if __name__ == "__main__":
    tests = [
        "application/json",
        "application/vnd.myapi.v2+json",
        "application/vnd.myapi.v3+json, application/json",
    ]
    for accept in tests:
        print(f"{accept!r} -> {parse_accept(accept)}")

Output

stdout
'application/json' -> v1
'application/vnd.myapi.v2+json' -> v2
'application/vnd.myapi.v3+json, application/json' -> v3

How it works

This example implements API version negotiation using the Accept header with vendor media types. The parse_accept function checks for exact substring matches of application/vnd.myapi.vN+json and returns the corresponding version string. In the HTTP handler, do_GET reads the header and echoes the version in a JSON response. Because the logic is centralized in parse_accept, the same function can be reused in tests or outside the server. The log_message override keeps console output clean so the printed results stay focused.

Common mistakes

  • Relying on simple `startswith` or ignoring the Accept header entirely can break version negotiation.
  • Forgetting to check for more specific versions before fallbacks — order matters when multiple vendor types are present.
  • Not handling missing Accept header, which should default to the oldest version.

Variations

  1. Use `acceptheader.parse` from the `accept` library for robust RFC-compliant parsing.
  2. Extract the version via regex like `re.search(r'v(\d+)\+json', accept)` for dynamic version lists.

Real-world use cases

  • Backend APIs decouple breaking changes by letting clients opt into v2 or v3 via explicit Accept headers.
  • Mobile app releases can target different API versions without changing URLs during gradual rollout.
  • Gateway or proxy layer reads the vendor Accept header to route requests to different microservice deployments.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from API design & gRPC

Related tutorials and quizzes for this topic.