Skip to main content

API Versioning & Deprecation

Versioning Model

SpeedPy uses URL-path versioning. Every resource endpoint lives under a version prefix:

/api/v1/me/
/api/v1/teams/
/api/v1/products/

The unversioned /api/ prefix is a dispatcher — it mounts versioned routes and shared infrastructure (schema, docs, auth). Individual endpoints must always be under a version prefix like /api/v1/....

Auth Endpoints

Authentication endpoints (/api/auth/token/, /api/auth/token/refresh/, /api/auth/token/revoke/) are intentionally unversioned. They are considered stable infrastructure and are not subject to the versioning lifecycle described below.

When to Add to v1 vs. Plan v2

Add to /api/v1/ (backward-compatible)

  • New endpoints
  • New optional request/response fields
  • New query parameters
  • New non-conflicting enum values
  • New HTTP methods on existing endpoints

Plan /api/v2/ (breaking changes)

  • Removing or renaming fields
  • Changing a field from optional to required (or vice versa)
  • Changing field semantics or data types
  • Removing endpoints
  • Changing URL structure
  • Changing authentication or permission requirements

When in doubt, prefer adding to v1 in a backward-compatible way.

Support Window

Once /api/v(N+1)/ is released, /api/vN/ continues to receive bug fixes and security patches for at least 12 months. After the support window closes, the old version may be removed.

Projects using SpeedPy as a boilerplate can adjust this window to fit their needs — 12 months is the recommended default.

Deprecation Pattern

SpeedPy defines a deprecation pattern for communicating upcoming removals. The pattern is documented here for use when needed — the boilerplate does not ship with active deprecations.

1. Mark in the OpenAPI Schema

Use drf-spectacular's extend_schema to mark deprecated endpoints or parameters:

from drf_spectacular.utils import extend_schema
from rest_framework.views import APIView
from rest_framework.response import Response


class OldEndpointView(APIView):
@extend_schema(deprecated=True)
def get(self, request):
return Response({"message": "Use /api/v2/new-endpoint/ instead"})

2. Return Sunset and Deprecation Headers

Add Deprecation and Sunset headers (RFC 8594) to signal when an endpoint will be removed:

from datetime import datetime
from rest_framework.response import Response
from rest_framework.views import APIView


class LegacyItemsView(APIView):
def get(self, request):
data = {"items": []}
response = Response(data)
response["Deprecation"] = "true"
response["Sunset"] = "Sat, 01 Mar 2026 00:00:00 GMT"
response["Link"] = '</docs/api-versioning>; rel="sunset"'
return response

The Sunset header value must be an HTTP-date indicating when the endpoint will stop functioning. The Link header should point to migration documentation.

3. Bump OpenAPI Schema Version

Update the info.version in the OpenAPI schema for each release that changes API surface:

  • Patch bump (e.g. 1.0.01.0.1): bug fixes, documentation changes
  • Minor bump (e.g. 1.0.01.1.0): new endpoints, new optional fields, deprecations
  • Major bump (e.g. 1.0.02.0.0): new /api/vN/ version introduced

This is configured in settings.py via SPECTACULAR_SETTINGS["VERSION"].

4. Document in the Changelog

Record all API changes in the Changelog under an API Changes section:

  • New endpoints or fields
  • Deprecations (with sunset date)
  • Removals
  • Migration guides for major version bumps

Summary

QuestionAnswer
Versioning schemeURL-path (/api/v1/..., /api/v2/...)
Auth endpoints versioned?No — unversioned and stable
Backward-compatible addition?Add to current version
Breaking change?New major version
Support window after new version12 months (configurable)
Deprecation signalDeprecation + Sunset headers, OpenAPI deprecated=True
Where to log changesChangelog, OpenAPI schema version bump