Generate typed response classes from the OpenAPI spec #40

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

Generate typed GDScript classes for the server's JSON responses from its OpenAPI spec, so field names and types stay in sync with MusicServer. Only the response types are generated; the requests stay hand-written in MusicServerClient (the API is small, and half of it returns audio bytes, which generators handle badly).

This replaces cmd/docs/generate_godot_openapi.py in MusicServer, which has been removed. It produced Godot 3/4 mixed code that doesn't parse in 4.7, overrode Object.call, shared one HTTPRequest between concurrent calls and ignored parameters and auth.

Input

  • The spec from a running server: GET <server>/openapi (Swagger 2.0 JSON, generated by swag). Or a copy committed to this repo, so builds don't need a server.
  • Types are under definitions, for example backend.SongInfo, backend.Soundtrack, backend.SoundtrackWithSongList, backend.Song, backend.SoundtrackWithSongs, backend.SongInfoForStats, backend.StatisticsSummary, backend.SyncResponse, backend.ProgressResponse, backend.VersionData, server.TokenResponse.

Output (Godot 4.7, following the GDScript style guide)

  • One file per type, for example server/generated/song_info.gd with class_name SongInfo extends RefCounted.
  • Typed properties (int, float, bool, String, typed Array[...], nested generated types via $ref).
  • static func from_dict(data: Dictionary) -> SongInfo that tolerates missing fields (defaults), and to_dict() if useful.
  • A header comment saying the file is generated and must not be edited.

Generator

  • Lives in this repo (MusicPlayer), for example as an @tool EditorScript or a small script under tools/, so the server repo doesn't need to know about Godot.
  • Deterministic output (sorted), so regenerating with no API changes gives no diff.

Acceptance criteria

  • Generated classes for the types used by the player
  • MusicServerClient callers use the typed classes instead of raw dictionaries for statistics and song info
  • A test that parses a sample JSON response for each class
Generate typed GDScript classes for the server's JSON responses from its OpenAPI spec, so field names and types stay in sync with MusicServer. Only the **response types** are generated; the requests stay hand-written in `MusicServerClient` (the API is small, and half of it returns audio bytes, which generators handle badly). This replaces `cmd/docs/generate_godot_openapi.py` in MusicServer, which has been removed. It produced Godot 3/4 mixed code that doesn't parse in 4.7, overrode `Object.call`, shared one `HTTPRequest` between concurrent calls and ignored parameters and auth. ## Input - The spec from a running server: `GET <server>/openapi` (Swagger 2.0 JSON, generated by swag). Or a copy committed to this repo, so builds don't need a server. - Types are under `definitions`, for example `backend.SongInfo`, `backend.Soundtrack`, `backend.SoundtrackWithSongList`, `backend.Song`, `backend.SoundtrackWithSongs`, `backend.SongInfoForStats`, `backend.StatisticsSummary`, `backend.SyncResponse`, `backend.ProgressResponse`, `backend.VersionData`, `server.TokenResponse`. ## Output (Godot 4.7, following the GDScript style guide) - One file per type, for example `server/generated/song_info.gd` with `class_name SongInfo extends RefCounted`. - Typed properties (`int`, `float`, `bool`, `String`, typed `Array[...]`, nested generated types via `$ref`). - `static func from_dict(data: Dictionary) -> SongInfo` that tolerates missing fields (defaults), and `to_dict()` if useful. - A header comment saying the file is generated and must not be edited. ## Generator - Lives in this repo (MusicPlayer), for example as an `@tool` EditorScript or a small script under `tools/`, so the server repo doesn't need to know about Godot. - Deterministic output (sorted), so regenerating with no API changes gives no diff. ## Acceptance criteria - Generated classes for the types used by the player - `MusicServerClient` callers use the typed classes instead of raw dictionaries for statistics and song info - A test that parses a sample JSON response for each class
Sansan added the improvement label 2026-10-06 16:11:39 +02:00
Author
Owner

Update: MusicServer now generates the spec with Huma. Use GET <server>/openapi.json (OpenAPI 3.1) or /openapi-3.0.json (OpenAPI 3.0) instead of the Swagger 2.0 file mentioned above. Types are under components.schemas (not definitions) with plain names: SongInfo, Soundtrack, SoundtrackWithSongList, Song, SoundtrackWithSongs, SongInfoForStats, StatisticsSummary, SyncResponse, ProgressResponse, VersionData, TokenResponse, APIError ({"error": string}). Arrays are never null, and fields without omitempty are listed as required.

**Update:** MusicServer now generates the spec with Huma. Use **`GET <server>/openapi.json`** (OpenAPI 3.1) or `/openapi-3.0.json` (OpenAPI 3.0) instead of the Swagger 2.0 file mentioned above. Types are under `components.schemas` (not `definitions`) with plain names: `SongInfo`, `Soundtrack`, `SoundtrackWithSongList`, `Song`, `SoundtrackWithSongs`, `SongInfoForStats`, `StatisticsSummary`, `SyncResponse`, `ProgressResponse`, `VersionData`, `TokenResponse`, `APIError` (`{"error": string}`). Arrays are never null, and fields without `omitempty` are listed as `required`.
Sign in to join this conversation.