Skip to content

chore: migrate API client to new /v1 route prefix#25

Merged
amrtgaber merged 1 commit into
mainfrom
chore/migrate-api-client-to-v1
May 13, 2026
Merged

chore: migrate API client to new /v1 route prefix#25
amrtgaber merged 1 commit into
mainfrom
chore/migrate-api-client-to-v1

Conversation

@amrtgaber
Copy link
Copy Markdown
Contributor

Closes #24

api-template moved every application route under a /v1 prefix in 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. This catches the web client up before it's pointed at an API built from the updated template.

Path map applied

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

What changed

5 files, +16/-12 — all hand-written API path strings:

  • src/api/api.ts — silent-refresh fetch() targets /v1/auth/refresh; the afterResponse "don't refresh on the refresh request" guard now matches /v1/auth/refresh and /v1/auth/jwt/logout.
  • src/lib/auth.tsxcheckAuth() calls /v1/auth/me; logout() calls /v1/auth/jwt/logout.
  • src/lib/feature-flags.tsxFeatureFlagProvider fetches /v1/flags.
  • src/api/handlers.ts — MSW default unauthenticated handler now matches */v1/auth/me.
  • README.md/auth/me, /auth/refresh, /flags references updated; documented that the refresh cookie is path-scoped to /v1/auth/refresh.

Codegen path note (from issue checklist): baseUrl stays the bare origin (VITE_API_URL, e.g. http://localhost:8000). The /v1 lives in the request paths — both in hand-written ky calls (api.get("v1/auth/me")) and in the orval-generated hooks (which produce strings like `/v1/auth/me`). Running pnpm generate-api against a /v1-prefixed spec drops them straight into the generated client; nothing in baseUrl to fight over, no /v1/v1/... duplication.

Dev proxy note: vite.config.ts has no server.proxy — this template uses CORS via VITE_API_URL, not a /api-style proxy. Nothing to rewrite there.

The generated orval client (src/api/generated/) is not committed — the template has never committed it, and the verify-api-types CI job is gated on vars.OPENAPI_URL. Consumers regenerate against their own backend.

Verification

Backend smoke test against a fresh api-template checkout of main (uv sync, alembic upgrade head, uv run uvicorn app.main:app):

  • Old unprefixed paths return 404: GET /auth/me, POST /auth/jwt/login, POST /auth/refresh, GET /flags, GET /notes.
  • Infrastructure paths return 200: /, /health, /docs, /openapi.json.
  • POST /v1/auth/register → 201 → POST /v1/auth/jwt/login → 204 with app_access (Path=/) and app_refresh (Path=/v1/auth/refresh).
  • GET /v1/auth/me with cookies → 200; GET /v1/notes → 200.
  • POST /v1/auth/refresh → 204 (cookies rotated, refresh cookie still Path=/v1/auth/refresh); subsequent GET /v1/auth/me with rotated cookies → 200.
  • POST /v1/auth/jwt/logout → 204; subsequent GET /v1/auth/me → 401.
  • Cookie-path scoping verified: GET /v1/auth/me carries only app_access; POST /v1/auth/refresh carries both. Confirms the frontend must request the exact path /v1/auth/refresh for the refresh cookie to be sent — which is what attemptRefresh() now does.

Codegen check: OPENAPI_URL=http://localhost:<port>/openapi.json pnpm generate-api produces hooks like useGetV1AuthMe calling `/v1/auth/me`, no /v1/v1/... duplication.

Local CI checks all green: pnpm lint (0 errors; the 4 fast-refresh warnings in src/routes/__root.tsx are pre-existing and the file isn't touched by this PR), pnpm format:check, pnpm tsc --noEmit, pnpm test:run (2/2). Husky pre-commit ran the production vite build cleanly.

Recommend a manual browser pass locally before merge: with VITE_API_URL=http://localhost:8000 and a /v1-prefixed api-template running, open http://localhost:5173 and confirm the initial GET /v1/auth/me (401) and GET /v1/flags requests fire in the network panel, with no /auth/me or /flags requests appearing.

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
@amrtgaber amrtgaber merged commit 4a60a8e into main May 13, 2026
2 checks passed
@amrtgaber amrtgaber deleted the chore/migrate-api-client-to-v1 branch May 13, 2026 05:54
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.

Migrate API client to the new /v1 route prefix

1 participant