Add OpenAPI contract and generated frontend client

This commit is contained in:
2026-02-18 21:25:07 +01:00
parent e55a1b01f4
commit 1802fd6607
19 changed files with 1509 additions and 126 deletions

867
openapi/GameList.json Normal file
View File

@@ -0,0 +1,867 @@
{
"openapi": "3.1.1",
"info": {
"title": "GameList | v1",
"version": "1.0.0"
},
"paths": {
"/health": {
"get": {
"tags": [
"GameList"
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/auth/options": {
"get": {
"tags": [
"Auth"
],
"operationId": "GetAuthOptions",
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/auth/register": {
"post": {
"tags": [
"Auth"
],
"operationId": "Register",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RegisterRequest"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/auth/login": {
"post": {
"tags": [
"Auth"
],
"operationId": "Login",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LoginRequest"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/auth/logout": {
"post": {
"tags": [
"Auth"
],
"operationId": "Logout",
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/state": {
"get": {
"tags": [
"State"
],
"operationId": "GetState",
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/events/state": {
"get": {
"tags": [
"State"
],
"operationId": "GetStateEvents",
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/me": {
"get": {
"tags": [
"State"
],
"operationId": "GetMe",
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/me/phase/next": {
"post": {
"tags": [
"State"
],
"operationId": "NextPhase",
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/me/phase/prev": {
"post": {
"tags": [
"State"
],
"operationId": "PrevPhase",
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/suggestions/mine": {
"get": {
"tags": [
"Suggestions"
],
"operationId": "GetMySuggestions",
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/suggestions": {
"post": {
"tags": [
"Suggestions"
],
"operationId": "CreateSuggestion",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SuggestionRequest"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/suggestions/{id}": {
"delete": {
"tags": [
"Suggestions"
],
"operationId": "DeleteSuggestion",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "OK"
}
}
},
"put": {
"tags": [
"Suggestions"
],
"operationId": "UpdateSuggestion",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"type": "integer",
"format": "int32"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SuggestionRequest"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/suggestions/all": {
"get": {
"tags": [
"Suggestions"
],
"operationId": "GetAllSuggestions",
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/votes/mine": {
"get": {
"tags": [
"Votes"
],
"operationId": "GetMyVotes",
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/votes": {
"post": {
"tags": [
"Votes"
],
"operationId": "UpsertVote",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/VoteRequest"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/votes/finalize": {
"post": {
"tags": [
"Votes"
],
"operationId": "SetVotesFinalized",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/VoteFinalizeRequest"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/results": {
"get": {
"tags": [
"Results"
],
"operationId": "GetResults",
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/admin/results": {
"post": {
"tags": [
"Admin"
],
"operationId": "SetResultsOpen",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ResultsOpenRequest"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/admin/vote-status": {
"get": {
"tags": [
"Admin"
],
"operationId": "GetVoteStatus",
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/admin/joker": {
"post": {
"tags": [
"Admin"
],
"operationId": "GrantJoker",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GrantJokerRequest"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/admin/player-phase": {
"post": {
"tags": [
"Admin"
],
"operationId": "SetPlayerPhase",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SetPlayerPhaseRequest"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/admin/player-admin": {
"post": {
"tags": [
"Admin"
],
"operationId": "SetPlayerAdmin",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SetPlayerAdminRequest"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/admin/players/{playerId}": {
"delete": {
"tags": [
"Admin"
],
"operationId": "DeletePlayer",
"parameters": [
{
"name": "playerId",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AdminPasswordRequest"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/admin/link-suggestions": {
"post": {
"tags": [
"Admin"
],
"operationId": "LinkSuggestions",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/LinkSuggestionsRequest"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/admin/unlink-suggestions": {
"post": {
"tags": [
"Admin"
],
"operationId": "UnlinkSuggestions",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UnlinkSuggestionsRequest"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/admin/reset": {
"post": {
"tags": [
"Admin"
],
"operationId": "Reset",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AdminPasswordRequest"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/api/admin/factory-reset": {
"post": {
"tags": [
"Admin"
],
"operationId": "FactoryReset",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AdminPasswordRequest"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "OK"
}
}
}
}
},
"components": {
"schemas": {
"AdminPasswordRequest": {
"required": [
"password"
],
"type": "object",
"properties": {
"password": {
"type": "string"
}
}
},
"GrantJokerRequest": {
"required": [
"playerId"
],
"type": "object",
"properties": {
"playerId": {
"type": "string",
"format": "uuid"
}
}
},
"LinkSuggestionsRequest": {
"required": [
"sourceSuggestionId",
"targetSuggestionId"
],
"type": "object",
"properties": {
"sourceSuggestionId": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"type": [
"integer",
"string"
],
"format": "int32"
},
"targetSuggestionId": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"type": [
"integer",
"string"
],
"format": "int32"
}
}
},
"LoginRequest": {
"required": [
"username",
"password"
],
"type": "object",
"properties": {
"username": {
"type": [
"null",
"string"
]
},
"password": {
"type": [
"null",
"string"
]
}
}
},
"Phase": {
"enum": [
"Suggest",
"Vote",
"Results"
]
},
"RegisterRequest": {
"required": [
"username",
"password",
"displayName",
"adminKey"
],
"type": "object",
"properties": {
"username": {
"type": [
"null",
"string"
]
},
"password": {
"type": [
"null",
"string"
]
},
"displayName": {
"type": [
"null",
"string"
]
},
"adminKey": {
"type": [
"null",
"string"
]
}
}
},
"ResultsOpenRequest": {
"required": [
"resultsOpen"
],
"type": "object",
"properties": {
"resultsOpen": {
"type": "boolean"
}
}
},
"SetPlayerAdminRequest": {
"required": [
"playerId",
"isAdmin"
],
"type": "object",
"properties": {
"playerId": {
"type": "string",
"format": "uuid"
},
"isAdmin": {
"type": "boolean"
}
}
},
"SetPlayerPhaseRequest": {
"required": [
"playerId",
"phase"
],
"type": "object",
"properties": {
"playerId": {
"type": "string",
"format": "uuid"
},
"phase": {
"$ref": "#/components/schemas/Phase"
}
}
},
"SuggestionRequest": {
"required": [
"name",
"genre",
"description",
"screenshotUrl",
"youtubeUrl",
"gameUrl",
"minPlayers",
"maxPlayers"
],
"type": "object",
"properties": {
"name": {
"type": "string"
},
"genre": {
"type": [
"null",
"string"
]
},
"description": {
"type": [
"null",
"string"
]
},
"screenshotUrl": {
"type": [
"null",
"string"
]
},
"youtubeUrl": {
"type": [
"null",
"string"
]
},
"gameUrl": {
"type": [
"null",
"string"
]
},
"minPlayers": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"type": [
"null",
"integer",
"string"
],
"format": "int32"
},
"maxPlayers": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"type": [
"null",
"integer",
"string"
],
"format": "int32"
}
}
},
"UnlinkSuggestionsRequest": {
"required": [
"suggestionId"
],
"type": "object",
"properties": {
"suggestionId": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"type": [
"integer",
"string"
],
"format": "int32"
}
}
},
"VoteFinalizeRequest": {
"required": [
"final"
],
"type": "object",
"properties": {
"final": {
"type": "boolean"
}
}
},
"VoteRequest": {
"required": [
"suggestionId",
"score"
],
"type": "object",
"properties": {
"suggestionId": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"type": [
"integer",
"string"
],
"format": "int32"
},
"score": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"type": [
"integer",
"string"
],
"format": "int32"
}
}
}
}
},
"tags": [
{
"name": "GameList"
},
{
"name": "Auth"
},
{
"name": "State"
},
{
"name": "Suggestions"
},
{
"name": "Votes"
},
{
"name": "Results"
},
{
"name": "Admin"
}
]
}