📝 consolidate multiple list endpoints for comics
This commit is contained in:
40
app.py
40
app.py
@@ -318,24 +318,19 @@ def terms():
|
||||
|
||||
@app.route('/api/comics')
|
||||
def api_comics():
|
||||
"""API endpoint - returns all comics as JSON"""
|
||||
"""API endpoint - returns all comics as JSON (optionally paginated with sections)"""
|
||||
# Check for pagination parameters
|
||||
page = request.args.get('page', type=int)
|
||||
per_page = request.args.get('per_page', type=int)
|
||||
group_by_section = request.args.get('group_by_section', 'false').lower() in ('true', '1', 'yes')
|
||||
|
||||
# If no pagination requested, return simple array (backward compatible)
|
||||
if page is None and per_page is None and not group_by_section:
|
||||
return jsonify([enrich_comic(comic) for comic in COMICS])
|
||||
|
||||
|
||||
@app.route('/api/comics/<int:comic_id>')
|
||||
def api_comic(comic_id):
|
||||
"""API endpoint - returns a specific comic as JSON"""
|
||||
comic = get_comic_by_number(comic_id)
|
||||
if not comic:
|
||||
return jsonify({'error': 'Comic not found'}), 404
|
||||
return jsonify(comic)
|
||||
|
||||
|
||||
@app.route('/api/archive')
|
||||
def api_archive():
|
||||
"""API endpoint - returns paginated archive data"""
|
||||
page = request.args.get('page', 1, type=int)
|
||||
per_page = request.args.get('per_page', 24, type=int)
|
||||
# Pagination requested - return paginated response
|
||||
page = page or 1
|
||||
per_page = per_page or 24
|
||||
|
||||
# Limit per_page to reasonable values
|
||||
per_page = min(max(per_page, 1), 100)
|
||||
@@ -343,8 +338,8 @@ def api_archive():
|
||||
# Reverse order to show newest first
|
||||
all_comics = [enrich_comic(comic) for comic in reversed(COMICS)]
|
||||
|
||||
# Group by section if enabled
|
||||
sections = group_comics_by_section(all_comics)
|
||||
# Group by section if enabled globally or requested via parameter
|
||||
sections = group_comics_by_section(all_comics) if (SECTIONS_ENABLED or group_by_section) else [(None, all_comics)]
|
||||
|
||||
# Calculate pagination
|
||||
total_comics = len(all_comics)
|
||||
@@ -388,6 +383,15 @@ def api_archive():
|
||||
})
|
||||
|
||||
|
||||
@app.route('/api/comics/<int:comic_id>')
|
||||
def api_comic(comic_id):
|
||||
"""API endpoint - returns a specific comic as JSON"""
|
||||
comic = get_comic_by_number(comic_id)
|
||||
if not comic:
|
||||
return jsonify({'error': 'Comic not found'}), 404
|
||||
return jsonify(comic)
|
||||
|
||||
|
||||
@app.route('/sitemap.xml')
|
||||
def sitemap():
|
||||
"""Serve the static sitemap.xml file"""
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
try {
|
||||
currentPage++;
|
||||
const response = await fetch(`/api/archive?page=${currentPage}&per_page=${perPage}`);
|
||||
const response = await fetch(`/api/comics?page=${currentPage}&per_page=${perPage}`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
|
||||
@@ -16,20 +16,59 @@ paths:
|
||||
/api/comics:
|
||||
get:
|
||||
summary: Get all comics
|
||||
description: Returns a list of all comics with enriched metadata including formatted dates and author notes
|
||||
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 with array of comics
|
||||
description: Successful response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
oneOf:
|
||||
- type: array
|
||||
description: Simple array response (when no pagination parameters provided)
|
||||
items:
|
||||
$ref: '#/components/schemas/Comic'
|
||||
example:
|
||||
- $ref: '#/components/schemas/PaginatedComicsResponse'
|
||||
examples:
|
||||
simpleArray:
|
||||
summary: Simple array response (default)
|
||||
value:
|
||||
- number: 1
|
||||
title: "First Comic"
|
||||
filename: "comic-001.jpg"
|
||||
@@ -49,6 +88,35 @@ paths:
|
||||
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:
|
||||
@@ -107,6 +175,9 @@ components:
|
||||
- plain
|
||||
- formatted_date
|
||||
- author_note_is_html
|
||||
- filenames
|
||||
- alt_texts
|
||||
- is_multi_image
|
||||
properties:
|
||||
number:
|
||||
type: integer
|
||||
@@ -118,9 +189,20 @@ components:
|
||||
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
|
||||
description: Image filename in static/images/comics/
|
||||
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
|
||||
@@ -131,13 +213,36 @@ components:
|
||||
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
|
||||
description: Accessibility text for the comic image
|
||||
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)
|
||||
@@ -155,6 +260,58 @@ components:
|
||||
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:
|
||||
|
||||
Reference in New Issue
Block a user