aboutsummaryrefslogtreecommitdiffhomepage
path: root/openapi
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-02-14 20:32:47 +0900
committernsfisis <nsfisis@gmail.com>2026-02-14 20:32:47 +0900
commit9185367fcd7d95af89fac36dd892d8b064dbd94f (patch)
tree6085f0c4ab695d0f83348f32b49b5481f1da6548 /openapi
parent6bd35e345a4c5d74578b0f8a5c969027e7e15f02 (diff)
downloadphperkaigi-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.yaml630
-rw-r--r--openapi/fortee.yaml52
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: {}