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 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.