FastAPI Backend Development Bootcamp · Leçon

Gestion des versions par URL, en-tête et type de média

Comparez les approches de gestion des versions et mettez en place un regroupement clair des routes pour permettre aux clients d’évoluer sans rupture.

Leçon 1 sur 413 étapes

Gestion des versions par URL, en-tête et type de média est une leçon FastAPI Backend Development Bootcamp gratuite sur CoddyKit. Ceci est la leçon 1 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage FastAPI Backend Development Bootcamp, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours FastAPI Backend Development Bootcamp comprend 4 leçons au total.

Certaines parties de cette leçon n'ont pas encore été traduites et s'affichent en anglais.

Why Version an API at All?

Once real clients depend on your API, you can no longer change a response shape freely. Renaming a field, removing a key, or changing a status code can break production apps you do not control.

Versioning lets you ship breaking changes under a new label while the old behavior keeps working. Clients upgrade on their own schedule.

  • Non-breaking change (add an optional field) usually needs no new version.
  • Breaking change (remove/rename a field, change types, change semantics) needs a version boundary.

This lesson compares the three classic strategies: URL path, Header, and Media-Type versioning.

Strategy 1: URL Path Versioning

The most common and most visible approach: put the version directly in the path, e.g. /v1/users and /v2/users.

  • Pros: obvious in logs and browsers, trivial to route, easy to cache, simple to document.
  • Cons: the version leaks into every URL; technically a URL should identify a resource, not a representation.

In FastAPI you express this with a prefix on an APIRouter. Each version gets its own router and its own prefix.

from fastapi import APIRouter, FastAPI

app = FastAPI()

v1 = APIRouter(prefix="/v1", tags=["v1"])
v2 = APIRouter(prefix="/v2", tags=["v2"])

@v1.get("/users/{user_id}")
def get_user_v1(user_id: int):
    return {"id": user_id, "name": "Ada Lovelace"}

@v2.get("/users/{user_id}")
def get_user_v2(user_id: int):
    # v2 splits name into first/last
    return {"id": user_id, "first_name": "Ada", "last_name": "Lovelace"}

app.include_router(v1)
app.include_router(v2)

Clean Route Grouping with Sub-Routers

Do not stack every endpoint onto one giant version router. Group by resource, then mount each resource router under the version router so structure stays clean as the API grows.

Here users_router is built independently and then included into v1. The combined path becomes /v1/users/....

from fastapi import APIRouter, FastAPI

app = FastAPI()

users_router = APIRouter(prefix="/users", tags=["users"])

@users_router.get("/{user_id}")
def get_user(user_id: int):
    return {"id": user_id, "name": "Grace Hopper"}

v1 = APIRouter(prefix="/v1")
v1.include_router(users_router)   # -> /v1/users/{user_id}

app.include_router(v1)

Strategy 2: Header Versioning

Here the URL stays clean (/users/42) and the client signals the version through a custom request header, commonly X-API-Version: 2.

  • Pros: URLs are version-free and stable; the resource path never changes.
  • Cons: harder to test in a browser, easy to forget the header, and caching layers must be told to vary on it.

In FastAPI you read the header with a typed parameter and branch (or dispatch) on it.

from fastapi import FastAPI, Header

app = FastAPI()

@app.get("/users/{user_id}")
def get_user(user_id: int, x_api_version: int = Header(default=1)):
    if x_api_version >= 2:
        return {"id": user_id, "first_name": "Ada", "last_name": "Lovelace"}
    return {"id": user_id, "name": "Ada Lovelace"}

A Dependency to Resolve the Version

Branching inside every endpoint gets messy. Extract the version logic into a reusable dependency that validates the header once and rejects unsupported versions with a clean 406.

Any endpoint can now depend on api_version and trust it is one of the supported values.

from fastapi import FastAPI, Header, HTTPException, Depends

app = FastAPI()
SUPPORTED = {1, 2}

def api_version(x_api_version: int = Header(default=1)) -> int:
    if x_api_version not in SUPPORTED:
        raise HTTPException(
            status_code=406,
            detail=f"Unsupported API version {x_api_version}",
        )
    return x_api_version

@app.get("/users/{user_id}")
def get_user(user_id: int, version: int = Depends(api_version)):
    return {"id": user_id, "version": version}

Strategy 3: Media-Type (Content Negotiation) Versioning

The most RESTful but least common approach. The client asks for a specific representation via the Accept header using a vendor media type:

  • Accept: application/vnd.myapp.v1+json
  • Accept: application/vnd.myapp.v2+json

The URL identifies the resource; the media type identifies the representation/version. This is true HTTP content negotiation.

  • Pros: URLs are clean and semantically pure; you version the representation, not the resource.
  • Cons: verbose, hard for casual clients, weak tooling support, easy to typo.

Parsing the Vendor Media Type

The core of media-type versioning is parsing the vendor string into a version number. That parsing is pure Python and easy to unit-test on its own, independent of any framework.

Below we extract the vN token from an Accept value, defaulting to v1 when it is missing or malformed.

import re

PATTERN = re.compile(r"application/vnd\.myapp\.v(\d+)\+json")

def parse_version(accept: str, default: int = 1) -> int:
    match = PATTERN.search(accept or "")
    return int(match.group(1)) if match else default

# A few quick checks
print(parse_version("application/vnd.myapp.v2+json"))  # 2
print(parse_version("application/json"))                # 1 (default)
print(parse_version("application/vnd.myapp.v10+json")) # 10

Wiring Media-Type Versioning into FastAPI

With the parser ready, plug it into a dependency that reads the Accept header. Endpoints stay clean and resource-focused while the version comes from content negotiation.

import re
from fastapi import FastAPI, Header, Depends

app = FastAPI()
PATTERN = re.compile(r"application/vnd\.myapp\.v(\d+)\+json")

def accept_version(accept: str = Header(default="")) -> int:
    m = PATTERN.search(accept)
    return int(m.group(1)) if m else 1

@app.get("/users/{user_id}")
def get_user(user_id: int, version: int = Depends(accept_version)):
    if version >= 2:
        return {"id": user_id, "first_name": "Ada", "last_name": "Lovelace"}
    return {"id": user_id, "name": "Ada Lovelace"}

Keeping Versions DRY with Transformers

Duplicating business logic per version rots fast. A cleaner pattern: compute the data once in a canonical internal shape, then run a small per-version transformer that adapts it to the contract each version promised.

This isolates contract differences in tiny, testable functions instead of forking your whole handler.

def canonical_user(user_id: int) -> dict:
    return {"id": user_id, "first": "Ada", "last": "Lovelace"}

def to_v1(u: dict) -> dict:
    return {"id": u["id"], "name": f"{u['first']} {u['last']}"}

def to_v2(u: dict) -> dict:
    return {"id": u["id"], "first_name": u["first"], "last_name": u["last"]}

VERSIONS = {1: to_v1, 2: to_v2}

def render(user_id: int, version: int) -> dict:
    return VERSIONS[version](canonical_user(user_id))

print(render(42, 1))  # {'id': 42, 'name': 'Ada Lovelace'}
print(render(42, 2))  # {'id': 42, 'first_name': 'Ada', 'last_name': 'Lovelace'}

Caching, Vary, and Documentation Pitfalls

Header and media-type versioning have a sharp edge: caches. If a proxy caches /users/42 without knowing about your version header, a v1 client may receive a cached v2 body.

  • Always send Vary: X-API-Version (or Vary: Accept for media-type versioning) so caches key on it.
  • URL versioning sidesteps this entirely because each version has a distinct URL.
  • Header/media-type versions are also harder to see in the auto-generated /docs schema, since the path looks identical across versions.

Choosing a Strategy and Deprecating Cleanly

Practical guidance for the bootcamp:

  • URL versioning is the default for public REST APIs: visible, cache-friendly, easy to onboard.
  • Header versioning suits internal services that want stable URLs and control both client and server.
  • Media-type versioning fits hypermedia/REST purists; rare in practice.

Whatever you pick, ship a deprecation plan: announce a sunset date, return a Deprecation/Sunset header on old versions, and keep them alive long enough for clients to migrate.

from fastapi import APIRouter
from fastapi.responses import JSONResponse

v1 = APIRouter(prefix="/v1")

@v1.get("/users/{user_id}")
def get_user_v1(user_id: int):
    body = {"id": user_id, "name": "Ada Lovelace"}
    headers = {
        "Deprecation": "true",
        "Sunset": "Wed, 31 Dec 2025 23:59:59 GMT",
        "Link": '</v2/users>; rel="successor-version"',
    }
    return JSONResponse(content=body, headers=headers)

Quick Check: Picking the Right Versioning Approach

Apply what you learned about the trade-offs between the three strategies.

Recap: Versioning Without Breakage

You compared three ways to version a FastAPI API:

  • URL path (/v1/users): visible, cache-friendly, easy to route via per-version APIRouter prefixes. The default for public APIs.
  • Header (X-API-Version): clean URLs, resolved with a dependency; remember Vary for caches.
  • Media-type (Accept: application/vnd.myapp.vN+json): purest REST, parsed from the Accept header; rare and verbose.

Keep routes grouped by resource and mounted under version routers, isolate contract differences in small per-version transformers, and always pair a new version with a clear deprecation/sunset plan so clients upgrade smoothly.

Gratuit pour commencer

Apprends FastAPI Backend Development Bootcamp avec un tuteur IA — gratuit

Écris et exécute du vrai code dans ton navigateur, obtiens de l'aide instantanée d'un tuteur IA disponible 24h/24, et reprends là où tu t'es arrêté sur le web ou dans l'app.

Cours
21
Leçons
84

Questions Fréquemment Posées

La leçon « Gestion des versions par URL, en-tête et type de média » est-elle gratuite ?

Oui — le texte complet de « Gestion des versions par URL, en-tête et type de média » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours FastAPI Backend Development Bootcamp, passe à CoddyKit PRO. Le cours FastAPI Backend Development Bootcamp comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Gestion des versions par URL, en-tête et type de média » ?

Comparez les approches de gestion des versions et mettez en place un regroupement clair des routes pour permettre aux clients d’évoluer sans rupture. Tu pratiques FastAPI Backend Development Bootcamp avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer FastAPI Backend Development Bootcamp ?

Aucune expérience préalable n'est requise. FastAPI Backend Development Bootcamp sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 1 sur 4.

Combien de temps prend la leçon « Gestion des versions par URL, en-tête et type de média » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon FastAPI Backend Development Bootcamp ?

Oui. Chaque leçon FastAPI Backend Development Bootcamp inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Gestion des versions par URL, en-tête et type de média
  2. Pagination par curseur ou décalage à grande échelle
  3. Paramètres de filtrage et de tri dynamiques
  4. Conception d’enveloppes de réponse stables
← Retour à FastAPI Backend Development Bootcamp