Skip to content

Mount all application routes under /v1#21

Merged
amrtgaber merged 1 commit into
mainfrom
feat/version-routes-under-v1
May 13, 2026
Merged

Mount all application routes under /v1#21
amrtgaber merged 1 commit into
mainfrom
feat/version-routes-under-v1

Conversation

@amrtgaber
Copy link
Copy Markdown
Contributor

What

Every application route — auth and business resources alike — is now served under a /v1 prefix, so the whole API surface can be versioned together. Infrastructure routes (/, /health, /docs, /openapi.json) stay unversioned.

Path changes:

Before After
/auth/register, /auth/jwt/login, /auth/jwt/logout, /auth/refresh, /auth/me /v1/auth/...
/admin/users/{id}/role /v1/admin/users/{id}/role
/notes, /notes/{id} /v1/notes, /v1/notes/{id}
/flags /v1/flags
/, /health, /docs, /openapi.json unchanged (infrastructure)

Why

vagrant-story-api recently went through a live migration to /v1 — a transitional dual-mount, a frontend migration, then removal of the old mount. A greenfield API generated from this template should never have to do that dance; baking /v1 in now makes it free.

How

  • API_V1_PREFIX lives in app/config.py as the single source of truth — a plain module constant, deliberately not env-overridable (the path version is part of the code contract, not deployment config). Mirrors FastAPI's own full-stack template (API_V1_STR).
  • app/main.py: the fastapi-users auth routers and the custom refresh/logout router are mounted under /v1/auth/...; the three resource routers are collected into a ROUTERS tuple and loop-mounted with the /v1 prefix. Adding a new resource router is now "append to the tuple".
  • The per-path auth rate limits (_AUTH_RATE_LIMITS) and the no-store cache-control check follow the new /v1/auth/ paths.
  • The refresh cookie's path moves to /v1/auth/refresh, derived from API_V1_PREFIX (via REFRESH_COOKIE_PATH in app/auth/refresh.py) so it can't silently drift from the endpoint it scopes.
  • Tests moved to /v1 paths; added TestRoutesAreVersioned asserting the unversioned path 404s and that /health stays unversioned.
  • README endpoint tables and the related auth/RBAC/feature-flag notes updated.

Follow-ups (separate issues)

  • web-template needs to regenerate its API client against the /v1 spec (and check for any hardcoded paths / dev-proxy config).
  • Add a global default rate limit (SlowAPIMiddleware + default_limits) — currently only the per-auth-path limits exist.
  • Add a /.well-known/security.txt.

Verification

uv run pytest — 29 passed. uv run ruff check . / ruff format --check . clean. App boots; route list confirmed (everything under /v1 except infra).

Every application route — auth and business resources — is now served
under a /v1 prefix so the whole API surface can be versioned together.
Infrastructure routes (/, /health, /docs, /openapi.json) stay
unversioned.

- API_V1_PREFIX in app/config.py is the single source of truth (not
  env-overridable — the path version is part of the code contract)
- main.py: auth routers mounted at /v1/auth/...; resource routers
  collected into a ROUTERS tuple and loop-mounted with the /v1 prefix
- per-path auth rate limits and the no-store cache-control check follow
  the new /v1/auth/ paths
- refresh cookie path moves to /v1/auth/refresh, derived from
  API_V1_PREFIX so it can't drift from the endpoint it scopes
- tests moved to /v1 paths; added a guard test asserting unversioned
  paths 404 and that health stays unversioned
- README endpoint tables and related notes updated

Baking this into the template now so APIs generated from it never have
to run the live unversioned-to-/v1 migration done in vagrant-story-api.
@amrtgaber
Copy link
Copy Markdown
Contributor Author

Follow-up issues (the PR body couldn't be edited — gh pr edit errors on a projectCards GraphQL deprecation for this repo):

@amrtgaber amrtgaber merged commit d359580 into main May 13, 2026
2 checks passed
@amrtgaber amrtgaber deleted the feat/version-routes-under-v1 branch May 13, 2026 03:55
amrtgaber added a commit to ag-tech-group/web-template that referenced this pull request May 13, 2026
api-template moved every application route under /v1
(ag-tech-group/api-template#21). Infrastructure routes (/, /health,
/docs, /openapi.json) stay unversioned. The refresh cookie is now
path-scoped to /v1/auth/refresh, so silent-refresh requests must hit
that exact path for the cookie to be sent.

Updated hand-written API paths:

- src/api/api.ts: silent-refresh fetches /v1/auth/refresh; afterResponse
  loop guard recognizes /v1/auth/refresh and /v1/auth/jwt/logout
- src/lib/auth.tsx: checkAuth -> /v1/auth/me; logout -> /v1/auth/jwt/logout
- src/lib/feature-flags.tsx: FeatureFlagProvider -> /v1/flags
- src/api/handlers.ts: MSW default handler -> /v1/auth/me
- README: corresponding path references and cookie-path note

baseUrl stays the bare origin (VITE_API_URL); /v1 lives in the request
paths so orval-generated hooks and hand-written ky calls share the same
contract and there's no /v1/v1/... duplication when pnpm generate-api is
re-run against the updated spec. No vite proxy entries to rewrite —
this template uses CORS via VITE_API_URL, not a dev proxy.

Closes #24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant