844 lines
23 KiB
YAML
844 lines
23 KiB
YAML
openapi: 3.0.4
|
||
info:
|
||
title: 'Titles, Users, Reviews, Tags, and Media API'
|
||
version: 1.0.0
|
||
servers:
|
||
- url: /api/v1
|
||
paths:
|
||
/titles:
|
||
get:
|
||
summary: Get titles
|
||
parameters:
|
||
- $ref: '#/components/parameters/cursor'
|
||
- $ref: '#/components/parameters/title_sort'
|
||
- name: sort_forward
|
||
in: query
|
||
schema:
|
||
type: boolean
|
||
default: true
|
||
- name: ext_search
|
||
in: query
|
||
schema:
|
||
type: boolean
|
||
default: false
|
||
- name: word
|
||
in: query
|
||
schema:
|
||
type: string
|
||
- name: status
|
||
in: query
|
||
description: List of title statuses to filter
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/TitleStatus'
|
||
explode: false
|
||
style: form
|
||
- name: rating
|
||
in: query
|
||
schema:
|
||
type: number
|
||
format: double
|
||
- name: release_year
|
||
in: query
|
||
schema:
|
||
type: integer
|
||
format: int32
|
||
- name: release_season
|
||
in: query
|
||
schema:
|
||
$ref: '#/components/schemas/ReleaseSeason'
|
||
- name: limit
|
||
in: query
|
||
schema:
|
||
type: integer
|
||
format: int32
|
||
default: 10
|
||
- name: offset
|
||
in: query
|
||
schema:
|
||
type: integer
|
||
format: int32
|
||
default: 0
|
||
- name: fields
|
||
in: query
|
||
schema:
|
||
type: string
|
||
default: all
|
||
responses:
|
||
'200':
|
||
description: List of titles with cursor
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
data:
|
||
description: List of titles
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Title'
|
||
cursor:
|
||
$ref: '#/components/schemas/CursorObj'
|
||
required:
|
||
- data
|
||
- cursor
|
||
'204':
|
||
description: No titles found
|
||
'400':
|
||
description: Request params are not correct
|
||
'500':
|
||
description: Unknown server error
|
||
'/titles/{title_id}':
|
||
get:
|
||
operationId: getTitle
|
||
summary: Get title description
|
||
parameters:
|
||
- name: title_id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
format: int64
|
||
- name: fields
|
||
in: query
|
||
schema:
|
||
type: string
|
||
default: all
|
||
responses:
|
||
'200':
|
||
description: Title description
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/Title'
|
||
'204':
|
||
description: No title found
|
||
'400':
|
||
description: Request params are not correct
|
||
'404':
|
||
description: Title not found
|
||
'500':
|
||
description: Unknown server error
|
||
security:
|
||
- JwtAuthCookies: []
|
||
/users/:
|
||
get:
|
||
summary: 'Search user by nickname or dispname (both in one param), response is always sorted by id'
|
||
parameters:
|
||
- name: word
|
||
in: query
|
||
schema:
|
||
type: string
|
||
- name: limit
|
||
in: query
|
||
schema:
|
||
type: integer
|
||
format: int32
|
||
default: 10
|
||
- name: cursor_id
|
||
in: query
|
||
description: pass cursor naked
|
||
schema:
|
||
type: integer
|
||
format: int32
|
||
default: 1
|
||
responses:
|
||
'200':
|
||
description: List of users with cursor
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
data:
|
||
description: List of users
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/User'
|
||
cursor:
|
||
type: integer
|
||
format: int64
|
||
default: 1
|
||
required:
|
||
- data
|
||
- cursor
|
||
'204':
|
||
description: No users found
|
||
'400':
|
||
description: Request params are not correct
|
||
'500':
|
||
description: Unknown server error
|
||
'/users/{user_id}':
|
||
get:
|
||
operationId: getUsersId
|
||
summary: Get user info
|
||
parameters:
|
||
- name: user_id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
- name: fields
|
||
in: query
|
||
schema:
|
||
type: string
|
||
default: all
|
||
responses:
|
||
'200':
|
||
description: User info
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/User'
|
||
'400':
|
||
description: Request params are not correct
|
||
'404':
|
||
description: User not found
|
||
'500':
|
||
description: Unknown server error
|
||
patch:
|
||
operationId: updateUser
|
||
summary: Partially update a user account
|
||
description: |
|
||
Update selected user profile fields (excluding password).
|
||
Password updates must be done via the dedicated auth-service (`/auth/`).
|
||
Fields not provided in the request body remain unchanged.
|
||
parameters:
|
||
- name: user_id
|
||
in: path
|
||
description: User ID (primary key)
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
format: int64
|
||
example: 123
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
description: Only provided fields are updated. Omitted fields remain unchanged.
|
||
type: object
|
||
properties:
|
||
avatar_id:
|
||
description: ID of the user avatar (references `images.id`); set to `null` to remove avatar
|
||
type: integer
|
||
format: int64
|
||
example: 42
|
||
nullable: true
|
||
mail:
|
||
description: User email (must be unique and valid)
|
||
type: string
|
||
format: email
|
||
example: john.doe.updated@example.com
|
||
pattern: '^[a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\\.[a-zA-Z0-9_-]+$'
|
||
nickname:
|
||
description: 'Username (alphanumeric + `_` or `-`, 3–16 chars)'
|
||
type: string
|
||
example: john_doe_43
|
||
maxLength: 16
|
||
minLength: 3
|
||
pattern: '^[a-zA-Z0-9_-]{3,16}$'
|
||
disp_name:
|
||
description: Display name
|
||
type: string
|
||
example: John Smith
|
||
maxLength: 32
|
||
user_desc:
|
||
description: User description / bio
|
||
type: string
|
||
example: Just a curious developer.
|
||
maxLength: 512
|
||
additionalProperties: false
|
||
responses:
|
||
'200':
|
||
description: User updated successfully. Returns updated user representation (excluding sensitive fields).
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/User'
|
||
'400':
|
||
description: 'Invalid input (e.g., validation failed, nickname/email conflict, malformed JSON)'
|
||
'401':
|
||
description: Unauthorized — missing or invalid authentication token
|
||
'403':
|
||
description: 'Forbidden — user is not allowed to modify this resource (e.g., not own profile & no admin rights)'
|
||
'404':
|
||
description: User not found
|
||
'409':
|
||
description: 'Conflict — e.g., requested `nickname` or `mail` already taken by another user'
|
||
'422':
|
||
description: 'Unprocessable Entity — semantic errors not caught by schema (e.g., invalid `avatar_id`)'
|
||
'500':
|
||
description: Unknown server error
|
||
security:
|
||
- XsrfAuthHeader: []
|
||
'/users/{user_id}/titles':
|
||
get:
|
||
operationId: getUserTitles
|
||
summary: Get user titles
|
||
parameters:
|
||
- $ref: '#/components/parameters/cursor'
|
||
- $ref: '#/components/parameters/title_sort'
|
||
- name: user_id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: string
|
||
- name: sort_forward
|
||
in: query
|
||
schema:
|
||
type: boolean
|
||
default: true
|
||
- name: word
|
||
in: query
|
||
schema:
|
||
type: string
|
||
- name: status
|
||
in: query
|
||
description: List of title statuses to filter
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/TitleStatus'
|
||
explode: false
|
||
style: form
|
||
- name: watch_status
|
||
in: query
|
||
schema:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/UserTitleStatus'
|
||
explode: false
|
||
style: form
|
||
- name: rating
|
||
in: query
|
||
schema:
|
||
type: number
|
||
format: double
|
||
- name: my_rate
|
||
in: query
|
||
schema:
|
||
type: integer
|
||
format: int32
|
||
- name: release_year
|
||
in: query
|
||
schema:
|
||
type: integer
|
||
format: int32
|
||
- name: release_season
|
||
in: query
|
||
schema:
|
||
$ref: '#/components/schemas/ReleaseSeason'
|
||
- name: limit
|
||
in: query
|
||
schema:
|
||
type: integer
|
||
format: int32
|
||
default: 10
|
||
- name: fields
|
||
in: query
|
||
schema:
|
||
type: string
|
||
default: all
|
||
responses:
|
||
'200':
|
||
description: List of user titles
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
data:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/UserTitle'
|
||
cursor:
|
||
$ref: '#/components/schemas/CursorObj'
|
||
required:
|
||
- data
|
||
- cursor
|
||
'204':
|
||
description: No titles found
|
||
'400':
|
||
description: Request params are not correct
|
||
'404':
|
||
description: User not found
|
||
'500':
|
||
description: Unknown server error
|
||
post:
|
||
operationId: addUserTitle
|
||
summary: Add a title to a user
|
||
description: 'User adding title to list af watched, status required'
|
||
parameters:
|
||
- name: user_id
|
||
in: path
|
||
description: ID of the user to assign the title to
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
format: int64
|
||
example: 123
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
title_id:
|
||
type: integer
|
||
format: int64
|
||
status:
|
||
$ref: '#/components/schemas/UserTitleStatus'
|
||
rate:
|
||
type: integer
|
||
format: int32
|
||
ftime:
|
||
type: string
|
||
format: date-time
|
||
required:
|
||
- title_id
|
||
- status
|
||
responses:
|
||
'200':
|
||
description: Title successfully added to user
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/UserTitleMini'
|
||
'400':
|
||
description: 'Invalid request body (missing fields, invalid types, etc.)'
|
||
'401':
|
||
description: Unauthorized — missing or invalid auth token
|
||
'403':
|
||
description: Forbidden — user not allowed to assign titles to this user
|
||
'404':
|
||
description: User or Title not found
|
||
'409':
|
||
description: Conflict — title already assigned to user (if applicable)
|
||
'500':
|
||
description: Internal server error
|
||
'/users/{user_id}/titles/{title_id}':
|
||
get:
|
||
operationId: getUserTitle
|
||
summary: Get user title
|
||
parameters:
|
||
- name: user_id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
format: int64
|
||
- name: title_id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
format: int64
|
||
responses:
|
||
'200':
|
||
description: User titles
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/UserTitleMini'
|
||
'204':
|
||
description: No user title found
|
||
'400':
|
||
description: Request params are not correct
|
||
'404':
|
||
description: User or title not found
|
||
'500':
|
||
description: Unknown server error
|
||
patch:
|
||
operationId: updateUserTitle
|
||
summary: Update a usertitle
|
||
description: User updating title list of watched
|
||
parameters:
|
||
- name: user_id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
format: int64
|
||
- name: title_id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
format: int64
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: object
|
||
properties:
|
||
status:
|
||
$ref: '#/components/schemas/UserTitleStatus'
|
||
rate:
|
||
type: integer
|
||
format: int32
|
||
ftime:
|
||
type: string
|
||
format: date-time
|
||
responses:
|
||
'200':
|
||
description: Title successfully updated
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/UserTitleMini'
|
||
'400':
|
||
description: 'Invalid request body (missing fields, invalid types, etc.)'
|
||
'401':
|
||
description: Unauthorized — missing or invalid auth token
|
||
'403':
|
||
description: Forbidden — user not allowed to update title
|
||
'404':
|
||
description: User or Title not found
|
||
'500':
|
||
description: Internal server error
|
||
security:
|
||
- XsrfAuthHeader: []
|
||
delete:
|
||
operationId: deleteUserTitle
|
||
summary: Delete a usertitle
|
||
description: User deleting title from list of watched
|
||
parameters:
|
||
- name: user_id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
format: int64
|
||
- name: title_id
|
||
in: path
|
||
required: true
|
||
schema:
|
||
type: integer
|
||
format: int64
|
||
responses:
|
||
'200':
|
||
description: Title successfully deleted
|
||
'401':
|
||
description: Unauthorized — missing or invalid auth token
|
||
'403':
|
||
description: Forbidden — user not allowed to delete title
|
||
'404':
|
||
description: User or Title not found
|
||
'500':
|
||
description: Internal server error
|
||
security:
|
||
- XsrfAuthHeader: []
|
||
/media/upload:
|
||
post:
|
||
summary: 'Upload an image (PNG, JPEG, or WebP)'
|
||
description: |
|
||
Uploads a single image file. Supported formats: **PNG**, **JPEG/JPG**, **WebP**.
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
encoding:
|
||
image:
|
||
contentType: 'image/png, image/jpeg, image/webp'
|
||
multipart/form-data:
|
||
schema:
|
||
image:
|
||
type: string
|
||
format: binary
|
||
description: 'Image file (PNG, JPEG, or WebP)'
|
||
responses:
|
||
'200':
|
||
description: Image uploaded successfully
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/Image'
|
||
'400':
|
||
description: 'Bad request — e.g., invalid/malformed image, empty file'
|
||
content:
|
||
application/json:
|
||
schema:
|
||
type: string
|
||
'415':
|
||
description: |
|
||
Unsupported Media Type — e.g., request `Content-Type` is not `multipart/form-data`,
|
||
or the `image` part has an unsupported `Content-Type` (not image/png, image/jpeg, or image/webp)
|
||
'500':
|
||
description: Internal server error
|
||
components:
|
||
parameters:
|
||
cursor:
|
||
in: query
|
||
name: cursor
|
||
required: false
|
||
schema:
|
||
type: string
|
||
title_sort:
|
||
in: query
|
||
name: sort
|
||
required: false
|
||
schema:
|
||
$ref: '#/components/schemas/TitleSort'
|
||
schemas:
|
||
TitleSort:
|
||
description: Title sort order
|
||
type: string
|
||
default: id
|
||
enum:
|
||
- id
|
||
- year
|
||
- rating
|
||
- views
|
||
TitleStatus:
|
||
description: Title status
|
||
type: string
|
||
enum:
|
||
- finished
|
||
- ongoing
|
||
- planned
|
||
ReleaseSeason:
|
||
description: Title release season
|
||
type: string
|
||
enum:
|
||
- winter
|
||
- spring
|
||
- summer
|
||
- fall
|
||
StorageType:
|
||
description: Image storage type
|
||
type: string
|
||
enum:
|
||
- s3
|
||
- local
|
||
Image:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
format: int64
|
||
storage_type:
|
||
$ref: '#/components/schemas/StorageType'
|
||
image_path:
|
||
type: string
|
||
Studio:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
format: int64
|
||
name:
|
||
type: string
|
||
poster:
|
||
$ref: '#/components/schemas/Image'
|
||
description:
|
||
type: string
|
||
required:
|
||
- id
|
||
- name
|
||
Tag:
|
||
description: 'A localized tag: keys are language codes (ISO 639-1), values are tag names'
|
||
type: object
|
||
example:
|
||
en: Shojo
|
||
ru: Сёдзё
|
||
ja: 少女
|
||
additionalProperties:
|
||
type: string
|
||
Tags:
|
||
description: Array of localized tags
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/Tag'
|
||
example:
|
||
- en: Shojo
|
||
ru: Сёдзё
|
||
ja: 少女
|
||
- en: Shounen
|
||
ru: Сёнен
|
||
ja: 少年
|
||
Title:
|
||
type: object
|
||
properties:
|
||
id:
|
||
description: Unique title ID (primary key)
|
||
type: integer
|
||
format: int64
|
||
example: 1
|
||
title_names:
|
||
description: 'Localized titles. Key = language (ISO 639-1), value = list of names'
|
||
type: object
|
||
example:
|
||
en:
|
||
- Attack on Titan
|
||
- AoT
|
||
ru:
|
||
- Атака титанов
|
||
- Титаны
|
||
ja:
|
||
- 進撃の巨人
|
||
additionalProperties:
|
||
type: array
|
||
items:
|
||
type: string
|
||
example: Attack on Titan
|
||
minItems: 1
|
||
example:
|
||
- Attack on Titan
|
||
- AoT
|
||
title_desc:
|
||
description: 'Localized description. Key = language (ISO 639-1), value = description.'
|
||
type: object
|
||
additionalProperties:
|
||
type: string
|
||
studio:
|
||
$ref: '#/components/schemas/Studio'
|
||
tags:
|
||
$ref: '#/components/schemas/Tags'
|
||
poster:
|
||
$ref: '#/components/schemas/Image'
|
||
title_status:
|
||
$ref: '#/components/schemas/TitleStatus'
|
||
rating:
|
||
type: number
|
||
format: double
|
||
rating_count:
|
||
type: integer
|
||
format: int32
|
||
release_year:
|
||
type: integer
|
||
format: int32
|
||
release_season:
|
||
$ref: '#/components/schemas/ReleaseSeason'
|
||
episodes_aired:
|
||
type: integer
|
||
format: int32
|
||
episodes_all:
|
||
type: integer
|
||
format: int32
|
||
episodes_len:
|
||
type: object
|
||
additionalProperties:
|
||
type: number
|
||
format: double
|
||
required:
|
||
- id
|
||
- title_names
|
||
- tags
|
||
CursorObj:
|
||
type: object
|
||
properties:
|
||
id:
|
||
type: integer
|
||
format: int64
|
||
param:
|
||
type: string
|
||
required:
|
||
- id
|
||
User:
|
||
type: object
|
||
properties:
|
||
id:
|
||
description: Unique user ID (primary key)
|
||
type: integer
|
||
format: int64
|
||
example: 1
|
||
image:
|
||
$ref: '#/components/schemas/Image'
|
||
mail:
|
||
description: User email
|
||
type: string
|
||
format: email
|
||
example: john.doe@example.com
|
||
nickname:
|
||
description: Username (alphanumeric + _ or -)
|
||
type: string
|
||
example: john_doe_42
|
||
maxLength: 16
|
||
disp_name:
|
||
description: Display name
|
||
type: string
|
||
example: John Doe
|
||
maxLength: 32
|
||
user_desc:
|
||
description: User description
|
||
type: string
|
||
example: Just a regular user.
|
||
maxLength: 512
|
||
creation_date:
|
||
description: Timestamp when the user was created
|
||
type: string
|
||
format: date-time
|
||
example: '2025-10-10T23:45:47.908073Z'
|
||
required:
|
||
- user_id
|
||
- nickname
|
||
UserTitleStatus:
|
||
description: User's title status
|
||
type: string
|
||
enum:
|
||
- finished
|
||
- planned
|
||
- dropped
|
||
- in-progress
|
||
UserTitle:
|
||
type: object
|
||
properties:
|
||
user_id:
|
||
type: integer
|
||
format: int64
|
||
title:
|
||
$ref: '#/components/schemas/Title'
|
||
status:
|
||
$ref: '#/components/schemas/UserTitleStatus'
|
||
rate:
|
||
type: integer
|
||
format: int32
|
||
review_id:
|
||
type: integer
|
||
format: int64
|
||
ctime:
|
||
type: string
|
||
format: date-time
|
||
required:
|
||
- user_id
|
||
- title_id
|
||
- status
|
||
UserTitleMini:
|
||
type: object
|
||
properties:
|
||
user_id:
|
||
type: integer
|
||
format: int64
|
||
title_id:
|
||
type: integer
|
||
format: int64
|
||
status:
|
||
$ref: '#/components/schemas/UserTitleStatus'
|
||
rate:
|
||
type: integer
|
||
format: int32
|
||
review_id:
|
||
type: integer
|
||
format: int64
|
||
ctime:
|
||
type: string
|
||
format: date-time
|
||
required:
|
||
- user_id
|
||
- title_id
|
||
- status
|
||
Review:
|
||
type: object
|
||
additionalProperties: true
|
||
securitySchemes:
|
||
XsrfAuthHeader:
|
||
type: apiKey
|
||
in: header
|
||
name: X-XSRF-TOKEN
|
||
description: |
|
||
Anti-CSRF token. Must match the `XSRF-TOKEN` cookie.
|
||
Required for all state-changing requests (POST/PUT/PATCH/DELETE).
|