|
|
openapi: "3.1.0"
|
|
|
|
|
|
info:
|
|
|
title: QuotesDB API
|
|
|
description: A simple quotes database with passphrase-based quote ownership.
|
|
|
version: "0.1.0"
|
|
|
license:
|
|
|
name: MIT OR Apache-2.0
|
|
|
|
|
|
servers:
|
|
|
- url: http://localhost:8787
|
|
|
description: Local development
|
|
|
- url: https://api.quotesdb.example.com
|
|
|
description: Production (Cloudflare Workers)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
# Security
|
|
|
# ---------------------------------------------------------------------------
|
|
|
# Auth is per-quote: each quote has a 4-word passphrase (auth_code) that was
|
|
|
# returned at creation time. Callers supply it via the X-Auth-Code header for
|
|
|
# mutating operations (POST /:id, DELETE /:id).
|
|
|
components:
|
|
|
securitySchemes:
|
|
|
AuthCode:
|
|
|
type: apiKey
|
|
|
in: header
|
|
|
name: X-Auth-Code
|
|
|
description: >
|
|
|
4-word passphrase returned when the quote was created
|
|
|
(e.g. ocean-table-purple-storm). Required for update and delete.
|
|
|
|
|
|
# -------------------------------------------------------------------------
|
|
|
# Schemas
|
|
|
# -------------------------------------------------------------------------
|
|
|
schemas:
|
|
|
|
|
|
# Returned for all GET responses — auth_code intentionally omitted.
|
|
|
Quote:
|
|
|
type: object
|
|
|
required:
|
|
|
- id
|
|
|
- text
|
|
|
- author
|
|
|
- tags
|
|
|
- created_at
|
|
|
- updated_at
|
|
|
properties:
|
|
|
id:
|
|
|
type: string
|
|
|
description: NanoID (~21 characters).
|
|
|
example: "V1StGXR8_Z5jdHi6B-myT"
|
|
|
text:
|
|
|
type: string
|
|
|
description: The quote text.
|
|
|
example: "The only way to do great work is to love what you do."
|
|
|
author:
|
|
|
type: string
|
|
|
description: The person attributed with the quote.
|
|
|
example: "Steve Jobs"
|
|
|
source:
|
|
|
type: ["string", "null"]
|
|
|
description: Optional source (book, speech, etc.).
|
|
|
example: "Stanford Commencement Address, 2005"
|
|
|
date:
|
|
|
type: ["string", "null"]
|
|
|
format: date
|
|
|
description: Optional ISO 8601 date (YYYY-MM-DD) associated with the quote.
|
|
|
example: "2005-06-12"
|
|
|
tags:
|
|
|
type: array
|
|
|
items:
|
|
|
type: string
|
|
|
description: Zero or more tags attached to the quote.
|
|
|
example: ["work", "inspiration"]
|
|
|
created_at:
|
|
|
type: string
|
|
|
format: date-time
|
|
|
description: When the quote was first stored (UTC).
|
|
|
updated_at:
|
|
|
type: string
|
|
|
format: date-time
|
|
|
description: When the quote was last modified (UTC).
|
|
|
|
|
|
# Returned only from the create (PUT) endpoint — includes auth_code.
|
|
|
QuoteCreated:
|
|
|
allOf:
|
|
|
- $ref: "#/components/schemas/Quote"
|
|
|
- type: object
|
|
|
required:
|
|
|
- auth_code
|
|
|
properties:
|
|
|
auth_code:
|
|
|
type: string
|
|
|
description: >
|
|
|
4-word passphrase that authorises future edits and deletes.
|
|
|
Store this — it cannot be recovered later.
|
|
|
example: "ocean-table-purple-storm"
|
|
|
|
|
|
# Request body for PUT /api/quotes (create).
|
|
|
QuoteCreateRequest:
|
|
|
type: object
|
|
|
required:
|
|
|
- text
|
|
|
- author
|
|
|
properties:
|
|
|
text:
|
|
|
type: string
|
|
|
description: The quote text.
|
|
|
author:
|
|
|
type: string
|
|
|
description: The person attributed with the quote.
|
|
|
source:
|
|
|
type: string
|
|
|
description: Optional source (book, speech, etc.).
|
|
|
date:
|
|
|
type: string
|
|
|
format: date
|
|
|
description: Optional ISO 8601 date (YYYY-MM-DD).
|
|
|
tags:
|
|
|
type: array
|
|
|
items:
|
|
|
type: string
|
|
|
description: Zero or more tags.
|
|
|
default: []
|
|
|
auth_code:
|
|
|
type: string
|
|
|
description: >
|
|
|
Optional custom auth code. If omitted, a 4-word passphrase is
|
|
|
auto-generated by the server and returned in the response.
|
|
|
|
|
|
# Request body for POST /api/quotes/:id (update — all fields optional).
|
|
|
QuoteUpdateRequest:
|
|
|
type: object
|
|
|
properties:
|
|
|
text:
|
|
|
type: string
|
|
|
description: Replacement quote text.
|
|
|
author:
|
|
|
type: string
|
|
|
description: Replacement author name.
|
|
|
source:
|
|
|
type: ["string", "null"]
|
|
|
description: Replacement source. Pass null to clear.
|
|
|
date:
|
|
|
type: ["string", "null"]
|
|
|
format: date
|
|
|
description: Replacement date. Pass null to clear.
|
|
|
tags:
|
|
|
type: array
|
|
|
items:
|
|
|
type: string
|
|
|
description: Replacement tag list. Replaces all existing tags.
|
|
|
|
|
|
# Paginated list of quotes.
|
|
|
QuoteList:
|
|
|
type: object
|
|
|
required:
|
|
|
- quotes
|
|
|
- page
|
|
|
- total_pages
|
|
|
- total_count
|
|
|
properties:
|
|
|
quotes:
|
|
|
type: array
|
|
|
items:
|
|
|
$ref: "#/components/schemas/Quote"
|
|
|
page:
|
|
|
type: integer
|
|
|
minimum: 1
|
|
|
description: Current page number.
|
|
|
total_pages:
|
|
|
type: integer
|
|
|
description: Total number of pages given the current filters.
|
|
|
total_count:
|
|
|
type: integer
|
|
|
description: Total number of quotes matching the current filters.
|
|
|
|
|
|
# Standard error envelope used by all error responses.
|
|
|
Error:
|
|
|
type: object
|
|
|
required:
|
|
|
- error
|
|
|
properties:
|
|
|
error:
|
|
|
type: string
|
|
|
description: Human-readable error message.
|
|
|
example: "quote not found"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
# Paths
|
|
|
# ---------------------------------------------------------------------------
|
|
|
# IMPORTANT — router registration order for the Rust implementation:
|
|
|
# GET /api/quotes/random must be registered BEFORE GET /api/quotes/{id}
|
|
|
# to prevent "random" being matched as an id parameter.
|
|
|
paths:
|
|
|
|
|
|
/api/:
|
|
|
get:
|
|
|
operationId: getOpenApiSpec
|
|
|
summary: OpenAPI specification
|
|
|
description: Returns this OpenAPI specification as JSON.
|
|
|
tags: [meta]
|
|
|
responses:
|
|
|
"200":
|
|
|
description: The OpenAPI spec in JSON format.
|
|
|
content:
|
|
|
application/json:
|
|
|
schema:
|
|
|
type: object
|
|
|
description: Raw OpenAPI 3.1 document.
|
|
|
|
|
|
/api/quotes:
|
|
|
get:
|
|
|
operationId: listQuotes
|
|
|
summary: List quotes
|
|
|
description: Returns a paginated list of quotes, optionally filtered by author or tag.
|
|
|
tags: [quotes]
|
|
|
parameters:
|
|
|
- name: page
|
|
|
in: query
|
|
|
description: Page number (1-based).
|
|
|
required: false
|
|
|
schema:
|
|
|
type: integer
|
|
|
minimum: 1
|
|
|
default: 1
|
|
|
- name: author
|
|
|
in: query
|
|
|
description: Filter by exact author name (case-insensitive).
|
|
|
required: false
|
|
|
schema:
|
|
|
type: string
|
|
|
- name: tag
|
|
|
in: query
|
|
|
description: Filter to quotes that have this tag.
|
|
|
required: false
|
|
|
schema:
|
|
|
type: string
|
|
|
- name: date_after_year
|
|
|
in: query
|
|
|
description: Only include quotes dated on or after this year.
|
|
|
required: false
|
|
|
schema:
|
|
|
type: integer
|
|
|
minimum: 0
|
|
|
maximum: 9999
|
|
|
- name: date_after_month
|
|
|
in: query
|
|
|
description: Narrows after-bound to this month (1–12). Requires date_after_year.
|
|
|
required: false
|
|
|
schema:
|
|
|
type: integer
|
|
|
minimum: 1
|
|
|
maximum: 12
|
|
|
- name: date_after_day
|
|
|
in: query
|
|
|
description: Narrows after-bound to this day (1–31). Requires date_after_year and date_after_month.
|
|
|
required: false
|
|
|
schema:
|
|
|
type: integer
|
|
|
minimum: 1
|
|
|
maximum: 31
|
|
|
- name: date_before_year
|
|
|
in: query
|
|
|
description: Only include quotes dated on or before this year.
|
|
|
required: false
|
|
|
schema:
|
|
|
type: integer
|
|
|
minimum: 0
|
|
|
maximum: 9999
|
|
|
- name: date_before_month
|
|
|
in: query
|
|
|
description: Narrows before-bound to this month (1–12). Requires date_before_year.
|
|
|
required: false
|
|
|
schema:
|
|
|
type: integer
|
|
|
minimum: 1
|
|
|
maximum: 12
|
|
|
- name: date_before_day
|
|
|
in: query
|
|
|
description: Narrows before-bound to this day (1–31). Requires date_before_year and date_before_month.
|
|
|
required: false
|
|
|
schema:
|
|
|
type: integer
|
|
|
minimum: 1
|
|
|
maximum: 31
|
|
|
responses:
|
|
|
"200":
|
|
|
description: Paginated list of quotes.
|
|
|
content:
|
|
|
application/json:
|
|
|
schema:
|
|
|
$ref: "#/components/schemas/QuoteList"
|
|
|
|
|
|
put:
|
|
|
operationId: createQuote
|
|
|
summary: Create a quote
|
|
|
description: >
|
|
|
Creates a new quote. If auth_code is omitted from the request body,
|
|
|
the server auto-generates a 4-word passphrase and returns it in the
|
|
|
response. Store the auth_code — it cannot be recovered later.
|
|
|
tags: [quotes]
|
|
|
requestBody:
|
|
|
required: true
|
|
|
content:
|
|
|
application/json:
|
|
|
schema:
|
|
|
$ref: "#/components/schemas/QuoteCreateRequest"
|
|
|
responses:
|
|
|
"201":
|
|
|
description: Quote created successfully.
|
|
|
content:
|
|
|
application/json:
|
|
|
schema:
|
|
|
$ref: "#/components/schemas/QuoteCreated"
|
|
|
"422":
|
|
|
description: Validation error (e.g. missing required fields).
|
|
|
content:
|
|
|
application/json:
|
|
|
schema:
|
|
|
$ref: "#/components/schemas/Error"
|
|
|
|
|
|
# NOTE: registered before /api/quotes/{id} in the Rust router.
|
|
|
/api/quotes/random:
|
|
|
get:
|
|
|
operationId: getRandomQuote
|
|
|
summary: Random quote
|
|
|
description: Returns a single randomly selected quote.
|
|
|
tags: [quotes]
|
|
|
responses:
|
|
|
"200":
|
|
|
description: A random quote.
|
|
|
content:
|
|
|
application/json:
|
|
|
schema:
|
|
|
$ref: "#/components/schemas/Quote"
|
|
|
"404":
|
|
|
description: No quotes exist in the database.
|
|
|
content:
|
|
|
application/json:
|
|
|
schema:
|
|
|
$ref: "#/components/schemas/Error"
|
|
|
|
|
|
/api/quotes/{id}:
|
|
|
parameters:
|
|
|
- name: id
|
|
|
in: path
|
|
|
required: true
|
|
|
description: NanoID of the quote (~21 characters).
|
|
|
schema:
|
|
|
type: string
|
|
|
example: "V1StGXR8_Z5jdHi6B-myT"
|
|
|
|
|
|
get:
|
|
|
operationId: getQuote
|
|
|
summary: Get a quote by ID
|
|
|
description: Returns a single quote identified by its NanoID.
|
|
|
tags: [quotes]
|
|
|
responses:
|
|
|
"200":
|
|
|
description: The requested quote.
|
|
|
content:
|
|
|
application/json:
|
|
|
schema:
|
|
|
$ref: "#/components/schemas/Quote"
|
|
|
"404":
|
|
|
description: Quote not found.
|
|
|
content:
|
|
|
application/json:
|
|
|
schema:
|
|
|
$ref: "#/components/schemas/Error"
|
|
|
|
|
|
post:
|
|
|
operationId: updateQuote
|
|
|
summary: Update a quote
|
|
|
description: >
|
|
|
Partially updates an existing quote. Only the fields included in the
|
|
|
request body are modified. Requires the quote's auth_code via the
|
|
|
X-Auth-Code header.
|
|
|
tags: [quotes]
|
|
|
security:
|
|
|
- AuthCode: []
|
|
|
requestBody:
|
|
|
required: true
|
|
|
content:
|
|
|
application/json:
|
|
|
schema:
|
|
|
$ref: "#/components/schemas/QuoteUpdateRequest"
|
|
|
responses:
|
|
|
"200":
|
|
|
description: The updated quote.
|
|
|
content:
|
|
|
application/json:
|
|
|
schema:
|
|
|
$ref: "#/components/schemas/Quote"
|
|
|
"403":
|
|
|
description: Auth code missing or incorrect.
|
|
|
content:
|
|
|
application/json:
|
|
|
schema:
|
|
|
$ref: "#/components/schemas/Error"
|
|
|
"404":
|
|
|
description: Quote not found.
|
|
|
content:
|
|
|
application/json:
|
|
|
schema:
|
|
|
$ref: "#/components/schemas/Error"
|
|
|
|
|
|
delete:
|
|
|
operationId: deleteQuote
|
|
|
summary: Delete a quote
|
|
|
description: >
|
|
|
Permanently deletes a quote. Requires the quote's auth_code via the
|
|
|
X-Auth-Code header.
|
|
|
tags: [quotes]
|
|
|
security:
|
|
|
- AuthCode: []
|
|
|
responses:
|
|
|
"204":
|
|
|
description: Quote deleted successfully. No response body.
|
|
|
"403":
|
|
|
description: Auth code missing or incorrect.
|
|
|
content:
|
|
|
application/json:
|
|
|
schema:
|
|
|
$ref: "#/components/schemas/Error"
|
|
|
"404":
|
|
|
description: Quote not found.
|
|
|
content:
|
|
|
application/json:
|
|
|
schema:
|
|
|
$ref: "#/components/schemas/Error"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
|
# Tags (for grouping in generated docs)
|
|
|
# ---------------------------------------------------------------------------
|
|
|
tags:
|
|
|
- name: meta
|
|
|
description: API metadata endpoints.
|
|
|
- name: quotes
|
|
|
description: CRUD operations on quotes.
|