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 '/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 '/users/{user_id}/titles': get: 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 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 patch: operationId: updateUserTitle summary: Update a usertitle description: User updating title list of watched 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 required: - title_id 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 delete: operationId: deleteUserTitle summary: Delete a usertitle description: User deleting title from list of watched parameters: - name: user_id in: path description: ID of the user to assign the title to required: true schema: type: integer format: int64 - name: title_id in: query 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 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 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