📝 api docs

This commit is contained in:
mi
2025-11-13 14:08:07 +10:00
parent bc2d4aebeb
commit d484835f5b
5 changed files with 207 additions and 3 deletions

6
app.py
View File

@@ -4,7 +4,8 @@ from flask import Flask, render_template, abort, jsonify, request
from comics_data import (
COMICS, FULL_WIDTH_DEFAULT, PLAIN_DEFAULT, HEADER_IMAGE, FOOTER_IMAGE,
COMPACT_FOOTER, USE_COMIC_NAV_ICONS, USE_HEADER_NAV_ICONS,
USE_FOOTER_SOCIAL_ICONS, SOCIAL_INSTAGRAM, SOCIAL_YOUTUBE, SOCIAL_EMAIL
USE_FOOTER_SOCIAL_ICONS, SOCIAL_INSTAGRAM, SOCIAL_YOUTUBE, SOCIAL_EMAIL,
API_SPEC_LINK
)
import markdown
@@ -26,7 +27,8 @@ def inject_global_settings():
'use_footer_social_icons': USE_FOOTER_SOCIAL_ICONS,
'social_instagram': SOCIAL_INSTAGRAM,
'social_youtube': SOCIAL_YOUTUBE,
'social_email': SOCIAL_EMAIL
'social_email': SOCIAL_EMAIL,
'api_spec_link': API_SPEC_LINK
}

View File

@@ -40,6 +40,10 @@ SOCIAL_INSTAGRAM = None # e.g., 'https://instagram.com/yourhandle'
SOCIAL_YOUTUBE = None # e.g., 'https://youtube.com/@yourchannel'
SOCIAL_EMAIL = None # e.g., 'mailto:your@email.com'
# API documentation link - set to None to hide the link
# Path is relative to static/ directory
API_SPEC_LINK = 'openapi.yaml' # Set to None to disable
COMICS = [
{
'number': 1,

View File

@@ -686,6 +686,18 @@ footer {
letter-spacing: var(--letter-spacing-tight);
}
.footer-bottom a.api-link {
color: var(--color-text);
text-decoration: none;
font-size: var(--font-size-md);
text-transform: uppercase;
letter-spacing: var(--letter-spacing-tight);
}
.footer-bottom a.api-link:hover {
text-decoration: underline;
}
/* Compact Footer Mode */
footer.compact-footer {
border-top: none;
@@ -698,6 +710,7 @@ footer.compact-footer .container {
align-items: center;
justify-content: center;
gap: var(--space-md);
flex-wrap: wrap;
}
footer.compact-footer .footer-content {
@@ -705,7 +718,7 @@ footer.compact-footer .footer-content {
align-items: center;
gap: var(--space-md);
margin-bottom: 0;
flex-wrap: nowrap;
flex-wrap: wrap;
}
footer.compact-footer .footer-section {
@@ -745,6 +758,8 @@ footer.compact-footer .footer-bottom {
padding-top: 0;
display: flex;
align-items: center;
flex-wrap: wrap;
gap: var(--space-xs);
}
footer.compact-footer .footer-bottom::before {
@@ -758,6 +773,16 @@ footer.compact-footer .footer-bottom p {
margin: 0;
}
footer.compact-footer .footer-bottom a.api-link {
font-size: var(--font-size-sm);
}
footer.compact-footer .footer-bottom a.api-link::before {
content: '|';
margin: 0 var(--space-sm);
color: var(--color-text-muted);
}
/* Add separator between sections in compact mode */
footer.compact-footer .footer-section:not(:last-child)::after {
content: '|';

170
static/openapi.yaml Normal file
View File

@@ -0,0 +1,170 @@
openapi: 3.0.3
info:
title: Sunday Comics API
description: API for accessing webcomic data from the Sunday Comics platform
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 a list of all comics with enriched metadata including formatted dates and author notes
operationId: getAllComics
tags:
- Comics
responses:
'200':
description: Successful response with array of comics
content:
application/json:
schema:
type: array
items:
$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
- 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
/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
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:
type: string
description: Image filename in static/images/comics/
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:
type: string
description: Accessibility text for the comic image
example: "The very first comic"
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!"
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
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

View File

@@ -130,6 +130,9 @@
<div class="footer-bottom">
<p>&copy; 2025 Sunday Comics. All rights reserved.</p>
{% if api_spec_link %}
<a href="{{ url_for('static', filename=api_spec_link) }}" class="api-link">API</a>
{% endif %}
</div>
</div>
</footer>