328 lines
11 KiB
YAML
328 lines
11 KiB
YAML
openapi: 3.0.3
|
|
info:
|
|
title: Webcomic API
|
|
description: API for accessing webcomic data
|
|
version: 1.0.0
|
|
contact:
|
|
url: http://127.0.0.1:3000
|
|
|
|
servers:
|
|
- url: http://127.0.0.1:3000
|
|
description: Development server
|
|
- url: https://your-production-domain.com
|
|
description: Production server (update with your actual domain)
|
|
|
|
paths:
|
|
/api/comics:
|
|
get:
|
|
summary: Get all comics
|
|
description: |
|
|
Returns all comics with enriched metadata. Supports optional pagination and section grouping.
|
|
|
|
**Without pagination parameters:** Returns a simple array of all comics (newest first when using pagination, original order otherwise).
|
|
|
|
**With pagination parameters:** Returns paginated response with section grouping (if enabled globally or via `group_by_section` parameter).
|
|
operationId: getAllComics
|
|
tags:
|
|
- Comics
|
|
parameters:
|
|
- name: page
|
|
in: query
|
|
description: Page number for pagination (1-indexed). When provided, triggers paginated response format.
|
|
required: false
|
|
schema:
|
|
type: integer
|
|
minimum: 1
|
|
default: 1
|
|
example: 1
|
|
- name: per_page
|
|
in: query
|
|
description: Number of comics per page (max 100). When provided, triggers paginated response format.
|
|
required: false
|
|
schema:
|
|
type: integer
|
|
minimum: 1
|
|
maximum: 100
|
|
default: 24
|
|
example: 24
|
|
- name: group_by_section
|
|
in: query
|
|
description: Force section grouping in response (even when SECTIONS_ENABLED is false). When true, triggers paginated response format.
|
|
required: false
|
|
schema:
|
|
type: boolean
|
|
default: false
|
|
example: false
|
|
responses:
|
|
'200':
|
|
description: Successful response
|
|
content:
|
|
application/json:
|
|
schema:
|
|
oneOf:
|
|
- type: array
|
|
description: Simple array response (when no pagination parameters provided)
|
|
items:
|
|
$ref: '#/components/schemas/Comic'
|
|
- $ref: '#/components/schemas/PaginatedComicsResponse'
|
|
examples:
|
|
simpleArray:
|
|
summary: Simple array response (default)
|
|
value:
|
|
- number: 1
|
|
title: "First Comic"
|
|
filename: "comic-001.jpg"
|
|
mobile_filename: "comic-001-mobile.jpg"
|
|
date: "2025-01-01"
|
|
alt_text: "The very first comic"
|
|
author_note: "This is where your comic journey begins!"
|
|
full_width: true
|
|
plain: true
|
|
formatted_date: "Wednesday, January 1, 2025"
|
|
author_note_is_html: false
|
|
- number: 2
|
|
filename: "comic-002.jpg"
|
|
date: "2025-01-08"
|
|
alt_text: "The second comic"
|
|
full_width: true
|
|
plain: true
|
|
formatted_date: "Wednesday, January 8, 2025"
|
|
author_note_is_html: false
|
|
paginatedResponse:
|
|
summary: Paginated response (when using page/per_page parameters)
|
|
value:
|
|
sections:
|
|
- section_title: "Chapter 1"
|
|
comics:
|
|
- number: 2
|
|
filename: "comic-002.jpg"
|
|
date: "2025-01-08"
|
|
alt_text: "The second comic"
|
|
full_width: true
|
|
plain: true
|
|
formatted_date: "Wednesday, January 8, 2025"
|
|
author_note_is_html: false
|
|
- section_title: null
|
|
comics:
|
|
- number: 1
|
|
title: "First Comic"
|
|
filename: "comic-001.jpg"
|
|
date: "2025-01-01"
|
|
alt_text: "The very first comic"
|
|
full_width: true
|
|
plain: true
|
|
formatted_date: "Wednesday, January 1, 2025"
|
|
author_note_is_html: false
|
|
page: 1
|
|
per_page: 24
|
|
total_comics: 2
|
|
has_more: false
|
|
|
|
/api/comics/{comic_id}:
|
|
get:
|
|
summary: Get a specific comic
|
|
description: Returns a single comic by its number/ID with enriched metadata
|
|
operationId: getComicById
|
|
tags:
|
|
- Comics
|
|
parameters:
|
|
- name: comic_id
|
|
in: path
|
|
description: Comic number/ID
|
|
required: true
|
|
schema:
|
|
type: integer
|
|
minimum: 1
|
|
example: 1
|
|
responses:
|
|
'200':
|
|
description: Successful response with comic data
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Comic'
|
|
example:
|
|
number: 1
|
|
title: "First Comic"
|
|
filename: "comic-001.jpg"
|
|
mobile_filename: "comic-001-mobile.jpg"
|
|
date: "2025-01-01"
|
|
alt_text: "The very first comic"
|
|
author_note: "This is where your comic journey begins!"
|
|
full_width: true
|
|
plain: true
|
|
formatted_date: "Wednesday, January 1, 2025"
|
|
author_note_is_html: false
|
|
'404':
|
|
description: Comic not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
example:
|
|
error: "Comic not found"
|
|
|
|
components:
|
|
schemas:
|
|
Comic:
|
|
type: object
|
|
required:
|
|
- number
|
|
- filename
|
|
- date
|
|
- alt_text
|
|
- full_width
|
|
- plain
|
|
- formatted_date
|
|
- author_note_is_html
|
|
- filenames
|
|
- alt_texts
|
|
- is_multi_image
|
|
properties:
|
|
number:
|
|
type: integer
|
|
description: Sequential comic number (unique identifier)
|
|
minimum: 1
|
|
example: 1
|
|
title:
|
|
type: string
|
|
description: Comic title (optional, defaults to "#X" if not provided)
|
|
example: "First Comic"
|
|
filename:
|
|
oneOf:
|
|
- type: string
|
|
description: Single image filename in static/images/comics/
|
|
- type: array
|
|
description: Multiple image filenames for webtoon-style comics
|
|
items:
|
|
type: string
|
|
example: "comic-001.jpg"
|
|
filenames:
|
|
type: array
|
|
description: Normalized array of image filenames (computed field, always an array even for single images)
|
|
items:
|
|
type: string
|
|
example: ["comic-001.jpg"]
|
|
mobile_filename:
|
|
type: string
|
|
description: Optional mobile version of the comic image
|
|
example: "comic-001-mobile.jpg"
|
|
date:
|
|
type: string
|
|
format: date
|
|
description: Publication date in YYYY-MM-DD format
|
|
example: "2025-01-01"
|
|
alt_text:
|
|
oneOf:
|
|
- type: string
|
|
description: Accessibility text for single image or shared text for all images
|
|
- type: array
|
|
description: Individual accessibility text for each image in multi-image comics
|
|
items:
|
|
type: string
|
|
example: "The very first comic"
|
|
alt_texts:
|
|
type: array
|
|
description: Normalized array of alt texts matching filenames (computed field)
|
|
items:
|
|
type: string
|
|
example: ["The very first comic"]
|
|
is_multi_image:
|
|
type: boolean
|
|
description: Indicates if this is a multi-image comic (computed field)
|
|
example: false
|
|
author_note:
|
|
type: string
|
|
description: Author's note about the comic (plain text or HTML from markdown)
|
|
example: "This is where your comic journey begins!"
|
|
author_note_md:
|
|
type: string
|
|
description: Filename or path to markdown file for author note
|
|
example: "2025-01-01.md"
|
|
section:
|
|
type: string
|
|
description: Section/chapter title (appears on archive page when SECTIONS_ENABLED is true)
|
|
example: "Chapter 1: Origins"
|
|
full_width:
|
|
type: boolean
|
|
description: Whether the comic should display in full-width mode (computed from global default and per-comic override)
|
|
example: true
|
|
plain:
|
|
type: boolean
|
|
description: Whether the comic should display in plain mode without header/borders (computed from global default and per-comic override)
|
|
example: true
|
|
formatted_date:
|
|
type: string
|
|
description: Human-readable formatted date (computed field)
|
|
example: "Wednesday, January 1, 2025"
|
|
author_note_is_html:
|
|
type: boolean
|
|
description: Indicates whether author_note contains HTML (from markdown) or plain text (computed field)
|
|
example: false
|
|
|
|
ComicSection:
|
|
type: object
|
|
required:
|
|
- section_title
|
|
- comics
|
|
properties:
|
|
section_title:
|
|
type: string
|
|
nullable: true
|
|
description: Section/chapter title (null for comics without a section)
|
|
example: "Chapter 1"
|
|
comics:
|
|
type: array
|
|
description: Comics in this section
|
|
items:
|
|
$ref: '#/components/schemas/Comic'
|
|
|
|
PaginatedComicsResponse:
|
|
type: object
|
|
required:
|
|
- sections
|
|
- page
|
|
- per_page
|
|
- total_comics
|
|
- has_more
|
|
properties:
|
|
sections:
|
|
type: array
|
|
description: Comics grouped by section
|
|
items:
|
|
$ref: '#/components/schemas/ComicSection'
|
|
page:
|
|
type: integer
|
|
description: Current page number
|
|
minimum: 1
|
|
example: 1
|
|
per_page:
|
|
type: integer
|
|
description: Number of comics per page
|
|
minimum: 1
|
|
maximum: 100
|
|
example: 24
|
|
total_comics:
|
|
type: integer
|
|
description: Total number of comics across all pages
|
|
minimum: 0
|
|
example: 100
|
|
has_more:
|
|
type: boolean
|
|
description: Whether there are more pages available
|
|
example: true
|
|
|
|
Error:
|
|
type: object
|
|
required:
|
|
- error
|
|
properties:
|
|
error:
|
|
type: string
|
|
description: Error message
|
|
example: "Comic not found"
|
|
|
|
tags:
|
|
- name: Comics
|
|
description: Operations for accessing comic data
|