mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-22 15:43:49 +01:00
feat(api): add DELETE /v2/characters/{id} route, v2 test coverage, and OpenAPI spec
Add REST-idiomatic DELETE method as alias for POST .../delete. Add 8 router-level tests exercising Bearer auth, invalid tokens, soft delete, export body decoding, and MaxLauncherHR capping. Create OpenAPI 3.1.0 specification covering all v2 endpoints.
This commit is contained in:
576
docs/openapi.yaml
Normal file
576
docs/openapi.yaml
Normal file
@@ -0,0 +1,576 @@
|
||||
openapi: 3.1.0
|
||||
info:
|
||||
title: Erupe API
|
||||
description: REST API for the Erupe Monster Hunter Frontier server emulator.
|
||||
version: 2.0.0
|
||||
license:
|
||||
name: MIT
|
||||
|
||||
servers:
|
||||
- url: http://localhost:8080
|
||||
description: Local development server
|
||||
|
||||
paths:
|
||||
/v2/login:
|
||||
post:
|
||||
summary: Authenticate user
|
||||
operationId: login
|
||||
tags: [auth]
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/LoginRequest"
|
||||
responses:
|
||||
"200":
|
||||
description: Successful authentication
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/AuthData"
|
||||
"400":
|
||||
description: Invalid credentials or malformed request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
examples:
|
||||
invalid_username:
|
||||
value:
|
||||
error: invalid_username
|
||||
message: Username not found
|
||||
invalid_password:
|
||||
value:
|
||||
error: invalid_password
|
||||
message: Incorrect password
|
||||
invalid_request:
|
||||
value:
|
||||
error: invalid_request
|
||||
message: Malformed request body
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalError"
|
||||
|
||||
/v2/register:
|
||||
post:
|
||||
summary: Create new user account
|
||||
operationId: register
|
||||
tags: [auth]
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/RegisterRequest"
|
||||
responses:
|
||||
"200":
|
||||
description: Account created successfully
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/AuthData"
|
||||
"400":
|
||||
description: Validation error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
examples:
|
||||
missing_fields:
|
||||
value:
|
||||
error: missing_fields
|
||||
message: Username and password required
|
||||
username_exists:
|
||||
value:
|
||||
error: username_exists
|
||||
message: Username already taken
|
||||
invalid_request:
|
||||
value:
|
||||
error: invalid_request
|
||||
message: Malformed request body
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalError"
|
||||
|
||||
/v2/launcher:
|
||||
get:
|
||||
summary: Get launcher UI data
|
||||
operationId: getLauncher
|
||||
tags: [public]
|
||||
responses:
|
||||
"200":
|
||||
description: Launcher banners, messages, and links
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/LauncherResponse"
|
||||
|
||||
/v2/version:
|
||||
get:
|
||||
summary: Get server version
|
||||
operationId: getVersion
|
||||
tags: [public]
|
||||
responses:
|
||||
"200":
|
||||
description: Server version information
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/VersionResponse"
|
||||
|
||||
/v2/health:
|
||||
get:
|
||||
summary: Health check
|
||||
operationId: getHealth
|
||||
tags: [public]
|
||||
responses:
|
||||
"200":
|
||||
description: Server is healthy
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/HealthResponse"
|
||||
"503":
|
||||
description: Server is unhealthy
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/HealthResponse"
|
||||
|
||||
/v2/server/status:
|
||||
get:
|
||||
summary: Get server status
|
||||
operationId: getServerStatus
|
||||
tags: [public]
|
||||
responses:
|
||||
"200":
|
||||
description: Current server status including events and MezFes schedule
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ServerStatusResponse"
|
||||
|
||||
/v2/characters:
|
||||
post:
|
||||
summary: Create a new character
|
||||
operationId: createCharacter
|
||||
tags: [characters]
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"200":
|
||||
description: Character created
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Character"
|
||||
"401":
|
||||
$ref: "#/components/responses/Unauthorized"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalError"
|
||||
|
||||
/v2/characters/{id}/delete:
|
||||
post:
|
||||
summary: Delete a character (POST form)
|
||||
operationId: deleteCharacterPost
|
||||
tags: [characters]
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/characterId"
|
||||
responses:
|
||||
"200":
|
||||
description: Character deleted
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
"401":
|
||||
$ref: "#/components/responses/Unauthorized"
|
||||
"400":
|
||||
description: Invalid character ID
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalError"
|
||||
|
||||
/v2/characters/{id}:
|
||||
delete:
|
||||
summary: Delete a character
|
||||
operationId: deleteCharacter
|
||||
tags: [characters]
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/characterId"
|
||||
responses:
|
||||
"200":
|
||||
description: Character deleted
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
"401":
|
||||
$ref: "#/components/responses/Unauthorized"
|
||||
"400":
|
||||
description: Invalid character ID
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalError"
|
||||
|
||||
/v2/characters/{id}/export:
|
||||
get:
|
||||
summary: Export character save data
|
||||
operationId: exportSave
|
||||
tags: [characters]
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/characterId"
|
||||
responses:
|
||||
"200":
|
||||
description: Full character data for backup
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ExportData"
|
||||
"401":
|
||||
$ref: "#/components/responses/Unauthorized"
|
||||
"400":
|
||||
description: Invalid character ID
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
"500":
|
||||
$ref: "#/components/responses/InternalError"
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
description: Session token returned by /v2/login or /v2/register
|
||||
|
||||
parameters:
|
||||
characterId:
|
||||
name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: uint32
|
||||
description: Character ID
|
||||
|
||||
responses:
|
||||
Unauthorized:
|
||||
description: Missing or invalid Bearer token
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
example:
|
||||
error: unauthorized
|
||||
message: Invalid or expired token
|
||||
InternalError:
|
||||
description: Internal server error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorResponse"
|
||||
example:
|
||||
error: internal_error
|
||||
message: Internal server error
|
||||
|
||||
schemas:
|
||||
ErrorResponse:
|
||||
type: object
|
||||
required: [error, message]
|
||||
properties:
|
||||
error:
|
||||
type: string
|
||||
description: Machine-readable error code
|
||||
examples:
|
||||
- invalid_username
|
||||
- invalid_password
|
||||
- username_exists
|
||||
- missing_fields
|
||||
- invalid_request
|
||||
- unauthorized
|
||||
- internal_error
|
||||
message:
|
||||
type: string
|
||||
description: Human-readable error description
|
||||
|
||||
LoginRequest:
|
||||
type: object
|
||||
required: [username, password]
|
||||
properties:
|
||||
username:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
|
||||
RegisterRequest:
|
||||
type: object
|
||||
required: [username, password]
|
||||
properties:
|
||||
username:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
|
||||
AuthData:
|
||||
type: object
|
||||
required:
|
||||
- currentTs
|
||||
- expiryTs
|
||||
- entranceCount
|
||||
- notices
|
||||
- user
|
||||
- characters
|
||||
- courses
|
||||
- mezFes
|
||||
- patchServer
|
||||
properties:
|
||||
currentTs:
|
||||
type: integer
|
||||
format: uint32
|
||||
description: Current server timestamp (Unix seconds)
|
||||
expiryTs:
|
||||
type: integer
|
||||
format: uint32
|
||||
description: Return expiry timestamp (Unix seconds)
|
||||
entranceCount:
|
||||
type: integer
|
||||
format: uint32
|
||||
notices:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
user:
|
||||
$ref: "#/components/schemas/User"
|
||||
characters:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Character"
|
||||
courses:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/CourseInfo"
|
||||
mezFes:
|
||||
oneOf:
|
||||
- $ref: "#/components/schemas/MezFes"
|
||||
- type: "null"
|
||||
patchServer:
|
||||
type: string
|
||||
|
||||
User:
|
||||
type: object
|
||||
required: [tokenId, token, rights]
|
||||
properties:
|
||||
tokenId:
|
||||
type: integer
|
||||
format: uint32
|
||||
token:
|
||||
type: string
|
||||
rights:
|
||||
type: integer
|
||||
format: uint32
|
||||
|
||||
Character:
|
||||
type: object
|
||||
required: [id, name, isFemale, weapon, hr, gr, lastLogin, returning]
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: uint32
|
||||
name:
|
||||
type: string
|
||||
isFemale:
|
||||
type: boolean
|
||||
weapon:
|
||||
type: integer
|
||||
format: uint32
|
||||
hr:
|
||||
type: integer
|
||||
format: uint32
|
||||
gr:
|
||||
type: integer
|
||||
format: uint32
|
||||
lastLogin:
|
||||
type: integer
|
||||
format: int32
|
||||
description: Unix timestamp of last login
|
||||
returning:
|
||||
type: boolean
|
||||
description: True if character has not logged in for 90+ days
|
||||
|
||||
CourseInfo:
|
||||
type: object
|
||||
required: [id, name]
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: uint16
|
||||
name:
|
||||
type: string
|
||||
|
||||
MezFes:
|
||||
type: object
|
||||
required: [id, start, end, soloTickets, groupTickets, stalls]
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: uint32
|
||||
start:
|
||||
type: integer
|
||||
format: uint32
|
||||
end:
|
||||
type: integer
|
||||
format: uint32
|
||||
soloTickets:
|
||||
type: integer
|
||||
format: uint32
|
||||
groupTickets:
|
||||
type: integer
|
||||
format: uint32
|
||||
stalls:
|
||||
type: array
|
||||
items:
|
||||
type: integer
|
||||
format: uint32
|
||||
|
||||
LauncherResponse:
|
||||
type: object
|
||||
required: [banners, messages, links]
|
||||
properties:
|
||||
banners:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Banner"
|
||||
messages:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Message"
|
||||
links:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Link"
|
||||
|
||||
Banner:
|
||||
type: object
|
||||
required: [src, link]
|
||||
properties:
|
||||
src:
|
||||
type: string
|
||||
description: Displayed image URL
|
||||
link:
|
||||
type: string
|
||||
description: Link accessed on click
|
||||
|
||||
Message:
|
||||
type: object
|
||||
required: [message, date, kind, link]
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
description: Displayed message
|
||||
date:
|
||||
type: integer
|
||||
format: int64
|
||||
description: Displayed date (Unix timestamp)
|
||||
kind:
|
||||
type: integer
|
||||
description: "0 = Default, 1 = New"
|
||||
enum: [0, 1]
|
||||
link:
|
||||
type: string
|
||||
description: Link accessed on click
|
||||
|
||||
Link:
|
||||
type: object
|
||||
required: [name, icon, link]
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description: Displayed name
|
||||
icon:
|
||||
type: string
|
||||
description: Displayed icon (rendered as monochrome if transparent)
|
||||
link:
|
||||
type: string
|
||||
description: Link accessed on click
|
||||
|
||||
VersionResponse:
|
||||
type: object
|
||||
required: [clientMode, name]
|
||||
properties:
|
||||
clientMode:
|
||||
type: string
|
||||
description: Supported game client version (e.g. "ZZ")
|
||||
name:
|
||||
type: string
|
||||
description: Server software name
|
||||
examples: ["Erupe-CE"]
|
||||
|
||||
HealthResponse:
|
||||
type: object
|
||||
required: [status]
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
enum: [ok, unhealthy]
|
||||
error:
|
||||
type: string
|
||||
description: Error description (present only when unhealthy)
|
||||
|
||||
ServerStatusResponse:
|
||||
type: object
|
||||
required: [mezFes, featuredWeapon, events]
|
||||
properties:
|
||||
mezFes:
|
||||
oneOf:
|
||||
- $ref: "#/components/schemas/MezFes"
|
||||
- type: "null"
|
||||
featuredWeapon:
|
||||
oneOf:
|
||||
- $ref: "#/components/schemas/FeatureWeaponInfo"
|
||||
- type: "null"
|
||||
events:
|
||||
$ref: "#/components/schemas/EventStatus"
|
||||
|
||||
FeatureWeaponInfo:
|
||||
type: object
|
||||
required: [startTime, activeFeatures]
|
||||
properties:
|
||||
startTime:
|
||||
type: integer
|
||||
format: uint32
|
||||
description: Unix timestamp
|
||||
activeFeatures:
|
||||
type: integer
|
||||
format: uint32
|
||||
description: Bitmask of active featured weapons
|
||||
|
||||
EventStatus:
|
||||
type: object
|
||||
required: [festaActive, divaActive]
|
||||
properties:
|
||||
festaActive:
|
||||
type: boolean
|
||||
divaActive:
|
||||
type: boolean
|
||||
|
||||
ExportData:
|
||||
type: object
|
||||
required: [character]
|
||||
properties:
|
||||
character:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
description: Full character database row as key-value pairs
|
||||
Reference in New Issue
Block a user