diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-02-14 20:32:47 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-02-14 20:32:47 +0900 |
| commit | 9185367fcd7d95af89fac36dd892d8b064dbd94f (patch) | |
| tree | 6085f0c4ab695d0f83348f32b49b5481f1da6548 /openapi | |
| parent | 6bd35e345a4c5d74578b0f8a5c969027e7e15f02 (diff) | |
| download | phperkaigi-2026-albatross-9185367fcd7d95af89fac36dd892d8b064dbd94f.tar.gz phperkaigi-2026-albatross-9185367fcd7d95af89fac36dd892d8b064dbd94f.tar.zst phperkaigi-2026-albatross-9185367fcd7d95af89fac36dd892d8b064dbd94f.zip | |
feat(openapi): generate OpenAPI specs from TypeSpec sources
Migrate hand-written OpenAPI YAML to TypeSpec (.tsp) source files.
TypeSpec compiles to OpenAPI 3.0 YAML, enabling type-safe API definitions.
- Add typespec/ directory with api-server and fortee definitions
- Integrate TypeSpec build into `just gen` and `just build` pipelines
- Update backend handler code to match new generated type names
(inlined error responses, separate GameType/ProblemLanguage enums)
- Regenerate frontend TypeScript types from new OpenAPI output
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'openapi')
| -rw-r--r-- | openapi/api-server.yaml | 630 | ||||
| -rw-r--r-- | openapi/fortee.yaml | 52 |
2 files changed, 371 insertions, 311 deletions
diff --git a/openapi/api-server.yaml b/openapi/api-server.yaml index 15b75b6..21fb989 100644 --- a/openapi/api-server.yaml +++ b/openapi/api-server.yaml @@ -2,75 +2,15 @@ openapi: 3.0.0 info: title: Albatross internal web API version: 0.3.0 +tags: [] paths: - /login: - post: - operationId: postLogin - summary: User login - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - username: - type: string - example: "john" - password: - type: string - example: "password123" - required: - - username - - password - responses: - '200': - description: Successfully authenticated - content: - application/json: - schema: - type: object - properties: - user: - $ref: '#/components/schemas/User' - required: - - user - '401': - $ref: '#/components/responses/Unauthorized' - /logout: - post: - operationId: postLogout - summary: User logout - responses: - '200': - description: Successfully logged out - '401': - $ref: '#/components/responses/Unauthorized' - /me: - get: - operationId: getMe - summary: Get current user - responses: - '200': - description: Current user info - content: - application/json: - schema: - type: object - properties: - user: - $ref: '#/components/schemas/User' - required: - - user - '401': - $ref: '#/components/responses/Unauthorized' /games: get: operationId: getGames - summary: List games + parameters: [] responses: '200': - description: List of games + description: The request has succeeded. content: application/json: schema: @@ -83,18 +23,29 @@ paths: required: - games '401': - $ref: '#/components/responses/Unauthorized' + description: Access is unauthorized. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '403': - $ref: '#/components/responses/Forbidden' + description: Access is forbidden. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /games/{game_id}: get: operationId: getGame - summary: Get a game parameters: - - $ref: '#/components/parameters/path_game_id' + - name: game_id + in: path + required: true + schema: + type: integer responses: '200': - description: A game + description: The request has succeeded. content: application/json: schema: @@ -105,41 +56,53 @@ paths: required: - game '401': - $ref: '#/components/responses/Unauthorized' + description: Access is unauthorized. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '403': - $ref: '#/components/responses/Forbidden' + description: Access is forbidden. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '404': - $ref: '#/components/responses/NotFound' - /games/{game_id}/play/latest_state: - get: - operationId: getGamePlayLatestState - summary: Get the latest execution result for player + description: The server cannot find the requested resource. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /games/{game_id}/play/code: + post: + operationId: postGamePlayCode parameters: - - $ref: '#/components/parameters/path_game_id' + - name: game_id + in: path + required: true + schema: + type: integer responses: '200': - description: Your latest game state + description: The request has succeeded. + '401': + description: Access is unauthorized. content: application/json: schema: - type: object - properties: - state: - $ref: '#/components/schemas/LatestGameState' - required: - - state - '401': - $ref: '#/components/responses/Unauthorized' + $ref: '#/components/schemas/Error' '403': - $ref: '#/components/responses/Forbidden' + description: Access is forbidden. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '404': - $ref: '#/components/responses/NotFound' - /games/{game_id}/play/code: - post: - operationId: postGamePlayCode - summary: Post the latest code - parameters: - - $ref: '#/components/parameters/path_game_id' + description: The server cannot find the requested resource. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' requestBody: required: true content: @@ -149,24 +112,77 @@ paths: properties: code: type: string - example: "echo 'hello world';" required: - code + /games/{game_id}/play/latest_state: + get: + operationId: getGamePlayLatestState + parameters: + - name: game_id + in: path + required: true + schema: + type: integer responses: '200': - description: Successfully updated + description: The request has succeeded. + content: + application/json: + schema: + type: object + properties: + state: + $ref: '#/components/schemas/LatestGameState' + required: + - state '401': - $ref: '#/components/responses/Unauthorized' + description: Access is unauthorized. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '403': - $ref: '#/components/responses/Forbidden' + description: Access is forbidden. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '404': - $ref: '#/components/responses/NotFound' + description: The server cannot find the requested resource. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /games/{game_id}/play/submit: post: operationId: postGamePlaySubmit - summary: Submit the answer parameters: - - $ref: '#/components/parameters/path_game_id' + - name: game_id + in: path + required: true + schema: + type: integer + responses: + '200': + description: The request has succeeded. + '401': + description: Access is unauthorized. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Access is forbidden. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: The server cannot find the requested resource. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' requestBody: required: true content: @@ -176,27 +192,61 @@ paths: properties: code: type: string - example: "echo 'hello world';" required: - code + /games/{game_id}/watch/latest_states: + get: + operationId: getGameWatchLatestStates + parameters: + - name: game_id + in: path + required: true + schema: + type: integer responses: '200': - description: Successfully submitted + description: The request has succeeded. + content: + application/json: + schema: + type: object + properties: + states: + type: object + additionalProperties: + $ref: '#/components/schemas/LatestGameState' + required: + - states '401': - $ref: '#/components/responses/Unauthorized' + description: Access is unauthorized. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '403': - $ref: '#/components/responses/Forbidden' + description: Access is forbidden. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '404': - $ref: '#/components/responses/NotFound' + description: The server cannot find the requested resource. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /games/{game_id}/watch/ranking: get: operationId: getGameWatchRanking - summary: Get the latest player ranking parameters: - - $ref: '#/components/parameters/path_game_id' + - name: game_id + in: path + required: true + schema: + type: integer responses: '200': - description: Player ranking + description: The request has succeeded. content: application/json: schema: @@ -209,70 +259,131 @@ paths: required: - ranking '401': - $ref: '#/components/responses/Unauthorized' + description: Access is unauthorized. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '403': - $ref: '#/components/responses/Forbidden' + description: Access is forbidden. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '404': - $ref: '#/components/responses/NotFound' - /games/{game_id}/watch/latest_states: + description: The server cannot find the requested resource. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /login: + post: + operationId: postLogin + parameters: [] + responses: + '200': + description: The request has succeeded. + content: + application/json: + schema: + type: object + properties: + user: + $ref: '#/components/schemas/User' + required: + - user + '401': + description: Access is unauthorized. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + username: + type: string + password: + type: string + required: + - username + - password + /logout: + post: + operationId: postLogout + parameters: [] + responses: + '200': + description: The request has succeeded. + '401': + description: Access is unauthorized. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /me: get: - operationId: getGameWatchLatestStates - summary: Get all the latest game states of the main players - parameters: - - $ref: '#/components/parameters/path_game_id' + operationId: getMe + parameters: [] responses: '200': - description: All the latest game states of the main players + description: The request has succeeded. content: application/json: schema: type: object properties: - states: - type: object - additionalProperties: - $ref: '#/components/schemas/LatestGameState' + user: + $ref: '#/components/schemas/User' required: - - states + - user '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '404': - $ref: '#/components/responses/NotFound' + description: Access is unauthorized. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' /tournament: get: operationId: getTournament - summary: Get tournament bracket data parameters: - - in: query - name: game1 + - name: game1 + in: query + required: true schema: type: integer + explode: false + - name: game2 + in: query required: true - - in: query - name: game2 schema: type: integer + explode: false + - name: game3 + in: query required: true - - in: query - name: game3 schema: type: integer + explode: false + - name: game4 + in: query required: true - - in: query - name: game4 schema: type: integer + explode: false + - name: game5 + in: query required: true - - in: query - name: game5 schema: type: integer - required: true + explode: false responses: '200': - description: Tournament data + description: The request has succeeded. content: application/json: schema: @@ -283,105 +394,66 @@ paths: required: - tournament '401': - $ref: '#/components/responses/Unauthorized' + description: Access is unauthorized. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '403': - $ref: '#/components/responses/Forbidden' + description: Access is forbidden. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' '404': - $ref: '#/components/responses/NotFound' + description: The server cannot find the requested resource. + content: + application/json: + schema: + $ref: '#/components/schemas/Error' components: - parameters: - path_game_id: - in: path - name: game_id - schema: - type: integer - required: true - responses: - BadRequest: - description: Bad request - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - Unauthorized: - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - Forbidden: - description: Forbidden - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - NotFound: - description: Not found - content: - application/json: - schema: - $ref: '#/components/schemas/Error' schemas: Error: type: object - properties: - message: - type: string - example: "Invalid request" required: - message - User: - type: object properties: - user_id: - type: integer - example: 123 - username: - type: string - example: "john" - display_name: - type: string - example: "John Doe" - icon_path: - type: string - example: "/images/john.jpg" - is_admin: - type: boolean - example: false - label: + message: type: string - nullable: true - example: "staff" - required: - - user_id - - username - - display_name - - is_admin - - label + ExecutionStatus: + type: string + enum: + - none + - running + - success + - wrong_answer + - timeout + - compile_error + - runtime_error + - internal_error Game: type: object + required: + - game_id + - game_type + - is_public + - display_name + - duration_seconds + - problem + - main_players properties: game_id: type: integer - example: 1 game_type: - type: string - example: "1v1" - enum: - - 1v1 - - multiplayer + $ref: '#/components/schemas/GameType' is_public: type: boolean - example: true display_name: type: string - example: "Game 1" duration_seconds: type: integer - example: 360 started_at: type: integer - example: 946684800 x-go-type: int64 problem: $ref: '#/components/schemas/Problem' @@ -389,123 +461,117 @@ components: type: array items: $ref: '#/components/schemas/User' - required: - - game_id - - game_type - - is_public - - display_name - - duration_seconds - - problem - - main_players - Problem: - type: object - properties: - problem_id: - type: integer - example: 1 - title: - type: string - example: "Problem 1" - description: - type: string - example: "This is a problem" - language: - type: string - example: "php" - enum: - - php - - swift - sample_code: - type: string - example: "echo 'hello world';" - required: - - problem_id - - title - - description - - language - - sample_code - ExecutionStatus: + GameType: type: string - example: "success" enum: - - none - - running - - success - - wrong_answer - - timeout - - compile_error - - runtime_error - - internal_error + - 1v1 + - multiplayer LatestGameState: type: object + required: + - code + - score + - best_score_submitted_at + - status properties: code: type: string - example: "echo 'hello world';" score: type: integer nullable: true - example: 100 best_score_submitted_at: type: integer nullable: true - example: 946684800 x-go-type: int64 status: $ref: '#/components/schemas/ExecutionStatus' + Problem: + type: object required: - - code - - score - - best_score_submitted_at - - status + - problem_id + - title + - description + - language + - sample_code + properties: + problem_id: + type: integer + title: + type: string + description: + type: string + language: + $ref: '#/components/schemas/ProblemLanguage' + sample_code: + type: string + ProblemLanguage: + type: string + enum: + - php + - swift RankingEntry: type: object + required: + - player + - score + - submitted_at + - code properties: player: $ref: '#/components/schemas/User' score: type: integer - example: 100 submitted_at: type: integer - example: 946684800 x-go-type: int64 code: type: string nullable: true - example: "echo 'hello world';" - required: - - player - - score - - submitted_at - - code Tournament: type: object + required: + - matches properties: matches: type: array items: $ref: '#/components/schemas/TournamentMatch' - required: - - matches TournamentMatch: type: object + required: + - game_id properties: game_id: type: integer - example: 1 player1: $ref: '#/components/schemas/User' player2: $ref: '#/components/schemas/User' player1_score: type: integer - example: 1 player2_score: type: integer - example: 1 winner: type: integer - example: 1 + User: + type: object required: - - game_id + - user_id + - username + - display_name + - is_admin + - label + properties: + user_id: + type: integer + username: + type: string + display_name: + type: string + icon_path: + type: string + is_admin: + type: boolean + label: + type: string + nullable: true diff --git a/openapi/fortee.yaml b/openapi/fortee.yaml index 7e27f30..89a1842 100644 --- a/openapi/fortee.yaml +++ b/openapi/fortee.yaml @@ -2,30 +2,15 @@ openapi: 3.0.0 info: title: fortee API version: 0.1.0 +tags: [] paths: /api/user/login: post: operationId: postLogin - summary: User login - requestBody: - required: true - content: - application/x-www-form-urlencoded: - schema: - type: object - properties: - username: - type: string - example: "john" - password: - type: string - example: "password123" - required: - - username - - password + parameters: [] responses: '200': - description: Successfully authenticated + description: The request has succeeded. content: application/json: schema: @@ -33,30 +18,41 @@ paths: properties: loggedIn: type: boolean - example: true user: type: object properties: username: type: string - example: "john" required: - username required: - loggedIn + requestBody: + required: true + content: + application/x-www-form-urlencoded: + schema: + type: object + properties: + username: + type: string + password: + type: string + required: + - username + - password /api/user/view/{username}: get: operationId: getUser - summary: Get a user parameters: - - in: path - name: username + - name: username + in: path + required: true schema: type: string - required: true responses: '200': - description: User found + description: The request has succeeded. content: application/json: schema: @@ -64,16 +60,14 @@ paths: properties: uuid: type: string - example: "11111111-1111-1111-1111-111111111111" username: type: string - example: "john" avatar_url: type: string - example: "/files/_user/11111111-1111-1111-1111-111111111111.jpg" required: - uuid - username - avatar_url '404': - description: User not found + description: The server cannot find the requested resource. +components: {} |
