Skip to content

fix: normalize REST paths, add security scheme, fix schema issues, add CI#8

Draft
jeremi wants to merge 13 commits into
GovStackWorkingGroup:mainfrom
jeremi:fix/scheduler-bb-api-quality
Draft

fix: normalize REST paths, add security scheme, fix schema issues, add CI#8
jeremi wants to merge 13 commits into
GovStackWorkingGroup:mainfrom
jeremi:fix/scheduler-bb-api-quality

Conversation

@jeremi
Copy link
Copy Markdown

@jeremi jeremi commented Apr 9, 2026

Summary

This PR brings the Scheduler BB OpenAPI spec in line with its own cross-cutting requirements and standard REST/OpenAPI conventions.

No new endpoints are added. Two endpoints are removed (PUT and DELETE on /log) because mutable audit logs contradict the spec's own audit logging requirements (sections 5.1.3 and 6.9). The remaining 35 operations map 1:1 to the original 35 (excluding the 2 removed).

Changes were validated with Spectral (0 errors, 0 warnings) and the OpenAPI spec validator. A GitHub Actions workflow is included to prevent regressions.

What changed

API paths (breaking)

All paths are normalized from RPC-style to REST conventions:

Before After
POST /event/new POST /event
PUT /event/modifications?event_id=X PUT /event/{event_id}
DELETE /event?event_id=X DELETE /event/{event_id}
GET /event/list_details?qry={...} POST /event/search (body)

Same pattern applied to all 9 resource types. Resource IDs moved from query params to path params. Creation and search payloads moved from qry query param (nested objects that cannot be serialized in URLs) to requestBody.

Security (breaking)

  • Added bearerAuth security scheme (HTTP bearer, JWT format) per section 5.1.4
  • Applied globally to all operations
  • Removed requestor_id and request_token query parameters (tokens in query strings appear in logs, browser history, and proxy caches)

Schema fixes

  • subscriber_limit: string to integer (event schemas)
  • lat/long in venue: string to number
  • format: url to format: uri (all URL fields), with valid URI examples
  • Boolean examples: "true" to true (appointment schemas)
  • free_slots: replaced malformed string with time_slot object array
  • days_hours.day_of_week example: "[monday" to "monday"
  • Array examples in 8 filter schemas: strings to actual arrays
  • free_resource_filter.Entity_id casing to entity_id
  • Normalized wrapper key in *_new_qry schemas to details (matching *_modify_qry)

Event slot model

Extracted a shared time_slot schema ({from, to} datetime pair). Used in:

  • event_creation_details.slots (array, multi-slot creation)
  • event_details.slot (single slot per event)
  • free_resource_details.free_slots

This resolves the inconsistency where creation used an inline slots array but read/update used flat from/to fields.

Response codes and required fields

  • POST create: 200 to 201 Created
  • DELETE: 200 to 204 No Content
  • Added 401 and 500 responses to all operations
  • Added required arrays to 9 creation/detail schemas (derived from spec section 7)

Pagination

All 10 search endpoints now return a {data, pagination} envelope with page, page_size, and total. Query parameters page (default 1) and page_size (default 20, max 100) are defined as reusable components.

Audit log integrity

Removed PUT /log/{log_id} and DELETE /log/{log_id}. The spec mandates audit logging (5.1.3 REQUIRED, 6.9) but the API allowed arbitrary modification and deletion of log records. Logs are now append-only + read-only.

Spec markdown

  • Fixed section numbering in 8-service-apis.md: 4.10-4.13 to 8.10-8.13
  • Updated all 35 swagger blocks to reference new paths/methods, removed 2 for deleted log endpoints
  • Updated all endpoint references in Mermaid diagrams in 9-workflows.md
  • Fixed SubscriberLimit type in 7-data-structures.md: String to Integer

CI

  • .spectral.yml with 7 custom rules + 3 built-in rules
  • .github/workflows/validate-api.yml triggered on changes to api/ or .spectral.yml
  • Warns on stale API files in spec/.gitbook/assets/

Housekeeping

  • Replaced hardcoded test server URL with parameterized template
  • Removed empty api/test.txt
  • Removed 10 orphaned *_list schemas (replaced by pagination envelope)
  • Fixed tag mismatch: subscribers to subscriber
  • Fixed subscriber/search response description (said "message list")
  • Added operationId to all 35 operations
  • Added description field to all 35 operations

Breaking changes

This PR changes every path and removes query-string auth. Any existing client code, test harness, or integration would need to update.

The Gherkin test harness in test/ references the old paths and would need corresponding updates. That work is not included here to keep the PR focused on the spec itself.

Not in scope

  • 4 missing interfaces (Information Mediator, PubSub, Messaging, Admin): The spec text acknowledges these as deferred ("should be the purpose of a next iteration"). These are scope gaps, not quality issues.
  • Stale API files in spec/.gitbook/assets/: 5 files with an older 33-path version. These may be managed by GitBook. After merge, the swagger blocks in 8-service-apis.md load from the main branch raw URL; if GitBook uses checked-in assets instead, there may be a visual inconsistency in published docs.
  • Structured error response schema: Error responses have descriptions but no response body schema. A shared error object would improve the spec further but is a separate concern.
  • 409 Conflict for deduplication: Sections 6.1 and 6.2 require duplicate detection, but no endpoint defines a conflict response. Worth adding in a follow-up.

Feedback requested

  1. required arrays on creation schemas: These are derived from spec section 7 but some are ambiguous. In particular, subscriber_details only requires ["name"], which may be too conservative. Please review and adjust.
  2. Gherkin test harness: The tests reference old paths. Happy to submit a follow-up PR updating the test suite if this direction is accepted.
  3. GitBook assets: Should the stale files in spec/.gitbook/assets/ be removed in this PR or left for GitBook to regenerate?

Validation

  • Spectral: 0 errors, 0 warnings
  • openapi-spec-validator: VALID
  • All $ref pointers resolve, no orphaned schemas

jeremi added 13 commits April 9, 2026 15:10
- Rename RPC-style paths to REST conventions: /event/new -> POST /event,
  /event/modifications -> PUT /event/{event_id}, /event -> DELETE /event/{event_id},
  /event/list_details -> POST /event/search. Same pattern for all 9 resource types.
- Move creation and search payloads from qry query params to requestBody
- Move resource IDs from query params to path params
- Remove requestor_id and request_token query params (security scheme in next commit)
- Add operationId to all 37 operations (camelCase verb+Resource convention)
- Fix content-type key from "json" to "application/json" on all search responses
Add bearerAuth securityScheme (HTTP bearer with JWT format) and apply it
globally, aligning the API with section 5.1.4 cross-cutting requirements.
- subscriber_limit: string -> integer in event schemas
- Boolean examples: "true" -> true in appointment schemas
- format: url -> uri on all URL fields
- lat/long: string -> number in venue schema
- day_of_week example: "[monday" -> "monday"
- free_slots: replace malformed string with proper object array
- event_ids example: "[1]" -> ["1"]
- Array examples in 8 filter schemas: string -> actual arrays
- Entity_id -> entity_id casing fix in free_resource_filter
Extract shared time_slot schema (from/to datetime pair) and use it in:
- event_creation_details.slots (array of time_slot, multi-slot creation)
- event_details.slot (single time_slot per event)
- free_resource_details.free_slots (array of time_slot)

This resolves the inconsistency where creation used an inline slots array
but read/update used flat from/to fields.
- POST create endpoints: 200 -> 201 Created
- DELETE endpoints: 200 -> 204 No Content
- Add 401 and 500 responses to all operations
- Add required arrays to 9 creation/detail schemas
- Fix tag mismatch: 'subscribers' -> 'subscriber' (matching operation usage)
- Add PageParam and PageSizeParam to components/parameters
- Add pagination_metadata schema (page, page_size, total)
- Wrap all 10 search endpoint responses in {data, pagination} envelope
- Pagination query params on all search and availability endpoints
Remove PUT /log/{log_id} and DELETE /log/{log_id} to make the log resource
append-only + read-only. Mutable audit logs contradict the spec's own
cross-cutting requirement 5.1.3 (audit logging) and section 6.9.
Also removes the orphaned log_modify_qry schema.
- Replace hardcoded test instance URL with parameterized server template
- Remove empty api/test.txt placeholder file
…ctures)

- Fix section numbering in 8-service-apis.md: 4.10-4.13 -> 8.10-8.13
- Update all 35 swagger blocks to reference new REST paths and methods
- Remove 2 swagger blocks for deleted log mutation endpoints
- Fix event creation endpoint in workflow diagram: Post/entity/new -> POST /event
- Update all endpoint references in Mermaid sequence diagrams throughout 9-workflows.md
- Fix SubscriberLimit type in 7-data-structures.md: String -> Integer
- Add .spectral.yml with 7 custom rules (security schemes, global security,
  no query-string auth, valid media types, 201 on create, 204 on delete,
  401 required) plus 3 built-in rules
- Add GitHub Actions workflow triggered on api/ and .spectral.yml changes
- Validated locally: 0 errors, warnings only for pre-existing issues
  (missing operation descriptions, unused list schemas, URI format examples)
Fixes found by staff engineer review:
- alert_schedule_details: required [name] -> [event_id, message_id, alert_datetime]
  (schema has no name property)
- message_details: required [name] -> [category, message_body]
  (schema has no name property)
- URI examples updated to valid URIs (https:// prefix)
- Trimmed leading whitespace in alert_preference examples
- Fixed subscriber/search response description ("message list" -> "subscriber list")
Rename {resource}_details -> details in 7 *_new_qry schemas to match
the convention already used by event_new_qry, entity_new_qry, and all
*_modify_qry schemas.
Copy summary text into description on all 35 operations to satisfy
the operation-description lint rule.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant