Switch to /api/v1 with token authentication #39

Closed
opened 2026-10-06 16:11:37 +02:00 by Sansan · 1 comment
Owner

Move all server calls from the deprecated legacy routes to /api/v1, with token authentication. The legacy routes still work but send a Deprecation: true header and will be removed later (see Sansan/MusicServer#31).

Do #38 (start sync with POST) first, or together with this.

Token flow

  • POST /api/v1/token with JSON {"password": "<API password>", "client_type": "godot"} returns {"token", "expires_at", "client_type"}. The token is valid for 24 hours.
  • Send it on every /api/v1 request: Authorization: Bearer <token>.
  • A missing, unknown or expired token returns 401 with {"error": "..."}.
  • Token creation is rate-limited to 10 requests per minute per client (429 when exceeded). Request a token once and reuse it, never per call.
  • If the server has no API_PASSWORD set, any password works. If it has DISABLE_SESSION_AUTH=true, no token is needed at all.
  • DELETE /api/v1/token invalidates the token, for example on quit.

Suggested structure

  • HttpTransport owns the token: it adds the Authorization header, and on a 401 it requests a new token once and retries the original request once. Callers don't need to know about tokens.
  • The password comes from settings (Settings), next to Settings.default_path. Don't hardcode it.
  • MusicServerClient prefixes paths with /api/v1. Everything else stays the same.
  • The fake transport in tests can simulate an expired token (first call 401, then 200) to test the retry.

Endpoint mapping

Legacy /api/v1
/music, /music/rand, /music/rand/low, /music/info, /music/list, /music/addQue, /music/reset, /music/played, /music/all, /music/all/order, /music/soundTest Same path under /api/v1/..., same responses
/characters /api/v1/character/list
/character?name= /api/v1/character?name=
POST /sync, GET /sync/progress POST /api/v1/sync, GET /api/v1/sync/progress
/version /api/v1/version
/download, /download/windows, /download/linux (for #12, #13) /api/v1/download/...
/health No v1 version; use GET /api/v1/version as a reachability check

Responses now also contain UUIDs: /music/info and /music/list have SoundtrackUuid and SongUuid. New UUID endpoints: GET /api/v1/soundtracks, /api/v1/soundtracks/{uuid}, /api/v1/songs/{uuid}, /api/v1/songs/{uuid}/file (streams the song).

The OpenAPI spec is served by the server at /openapi (Swagger UI at /swagger/index.html).

Acceptance criteria

  • No calls to legacy routes remain
  • Token requested once, reused, and refreshed automatically on 401
  • Password configurable in settings
  • Unit tests for token handling (header added, refresh + retry on 401, only one retry)
Move all server calls from the deprecated legacy routes to `/api/v1`, with token authentication. The legacy routes still work but send a `Deprecation: true` header and will be removed later (see Sansan/MusicServer#31). Do #38 (start sync with POST) first, or together with this. ## Token flow - `POST /api/v1/token` with JSON `{"password": "<API password>", "client_type": "godot"}` returns `{"token", "expires_at", "client_type"}`. The token is valid for **24 hours**. - Send it on every `/api/v1` request: `Authorization: Bearer <token>`. - A missing, unknown or expired token returns **401** with `{"error": "..."}`. - Token creation is rate-limited to **10 requests per minute per client** (429 when exceeded). Request a token once and reuse it, never per call. - If the server has no `API_PASSWORD` set, any password works. If it has `DISABLE_SESSION_AUTH=true`, no token is needed at all. - `DELETE /api/v1/token` invalidates the token, for example on quit. ## Suggested structure - **`HttpTransport`** owns the token: it adds the `Authorization` header, and on a 401 it requests a new token once and retries the original request once. Callers don't need to know about tokens. - The password comes from settings (`Settings`), next to `Settings.default_path`. Don't hardcode it. - **`MusicServerClient`** prefixes paths with `/api/v1`. Everything else stays the same. - The fake transport in tests can simulate an expired token (first call 401, then 200) to test the retry. ## Endpoint mapping | Legacy | `/api/v1` | |---|---| | `/music`, `/music/rand`, `/music/rand/low`, `/music/info`, `/music/list`, `/music/addQue`, `/music/reset`, `/music/played`, `/music/all`, `/music/all/order`, `/music/soundTest` | Same path under `/api/v1/...`, same responses | | `/characters` | `/api/v1/character/list` | | `/character?name=` | `/api/v1/character?name=` | | `POST /sync`, `GET /sync/progress` | `POST /api/v1/sync`, `GET /api/v1/sync/progress` | | `/version` | `/api/v1/version` | | `/download`, `/download/windows`, `/download/linux` (for #12, #13) | `/api/v1/download/...` | | `/health` | No v1 version; use `GET /api/v1/version` as a reachability check | Responses now also contain UUIDs: `/music/info` and `/music/list` have `SoundtrackUuid` and `SongUuid`. New UUID endpoints: `GET /api/v1/soundtracks`, `/api/v1/soundtracks/{uuid}`, `/api/v1/songs/{uuid}`, `/api/v1/songs/{uuid}/file` (streams the song). The OpenAPI spec is served by the server at `/openapi` (Swagger UI at `/swagger/index.html`). ## Acceptance criteria - No calls to legacy routes remain - Token requested once, reused, and refreshed automatically on 401 - Password configurable in settings - Unit tests for token handling (header added, refresh + retry on 401, only one retry)
Sansan added the improvement label 2026-10-06 16:11:37 +02:00
Author
Owner

Update from MusicServer (develop, commit 973ebf2): the API docs are now generated with Huma instead of swag.

  • Spec: OpenAPI 3.1 at /openapi.json (also /openapi.yaml, and OpenAPI 3.0 at /openapi-3.0.json). Interactive docs at /docs. /openapi redirects to /openapi.json. Only /api/v1 is documented; legacy routes are hidden but still work.
  • Health: GET /api/v1/health now exists and needs no token (returns {"status": "up"}).
  • Sync aliases removed: /sync/new, /sync/quick and /sync/new/full are gone. Use POST /sync and POST /sync/full.
  • Errors: every error body is {"error": "..."}. Invalid or missing parameters (for example ?song=abc, a malformed UUID, limit=0) now return 422 instead of 400.
  • Lists: empty lists are [], never null. Arrays in the spec are not nullable.
**Update from MusicServer (`develop`, commit 973ebf2):** the API docs are now generated with Huma instead of swag. - **Spec:** OpenAPI 3.1 at `/openapi.json` (also `/openapi.yaml`, and OpenAPI 3.0 at `/openapi-3.0.json`). Interactive docs at `/docs`. `/openapi` redirects to `/openapi.json`. Only `/api/v1` is documented; legacy routes are hidden but still work. - **Health:** `GET /api/v1/health` now exists and needs no token (returns `{"status": "up"}`). - **Sync aliases removed:** `/sync/new`, `/sync/quick` and `/sync/new/full` are gone. Use `POST /sync` and `POST /sync/full`. - **Errors:** every error body is `{"error": "..."}`. Invalid or missing parameters (for example `?song=abc`, a malformed UUID, `limit=0`) now return **422** instead of 400. - **Lists:** empty lists are `[]`, never `null`. Arrays in the spec are not nullable.
Sign in to join this conversation.