Skip to content

feat: enhance openapi docs for agents - #1674

Open
3kh0 wants to merge 1 commit into
mainfrom
openapi
Open

feat: enhance openapi docs for agents#1674
3kh0 wants to merge 1 commit into
mainfrom
openapi

Conversation

@3kh0

@3kh0 3kh0 commented Sep 3, 2026

Copy link
Copy Markdown
Member

Summary of the problem

API clients and agents need a machine-readable description of the public API. The canonical location is /openapi.json, but there are also conventional aliases at /openapi.yaml, /api/openapi.json, and /api/openapi.yaml. The document is generated from the existing rswag spec, so it is always up to date.

Describe your changes

New endpoints (app/controllers/openapi_controller.rb, config/routes.rb)

  • GET /openapi.json (canonical) and GET /openapi.yaml, aliased at /api/openapi.json and /api/openapi.yaml
  • Served from swagger/v1/swagger.yaml, so rswag stays the single source of truth. JSON is converted and memoised; YAML is the raw file
  • application/json / application/yaml (RFC 9512), Cache-Control: public, max-age=3600 (overriding the app-wide no-store), Access-Control-Allow-Origin: *, ETag revalidation via Rack

Discovery

  • <link rel="service-desc" href="/openapi.json"> and <link rel="service-doc" href="/api-docs"> in the shared layout head (RFC 8631) — emitted on every page
  • robots.txt now explicitly allows the four spec paths and /api-docs (the longer Allow beats the existing Disallow: /api/)
  • docs/index.mdx API card mentions /openapi.json

Spec quality fixes (needed for the published document to be valid and useful)

  • Fixed two OpenAPI structure violations: format sat at parameter level instead of inside schema on /api/hackatime/v1/users/{id}/summaries (start, end)
  • Added explicit security: [] to the 11 endpoints callable without credentials, and the optional-auth form [{}, {Bearer}, {ApiKeyAuth}] to the five user-stats endpoints, matching the pattern already used for /api/v1/users/{username}/stats
  • Added info.license (MIT), info.contact, and externalDocs to both specs
  • The discovery endpoints are themselves documented under a Discovery tag, so the document describes how to fetch itself

Screenshots / Media

n/a

@greptile-apps

greptile-apps Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR publishes the rswag-generated public OpenAPI document through JSON and YAML discovery endpoints and advertises it through page metadata, robots.txt, and documentation.

  • Adds four public OpenAPI routes with cache and CORS headers.
  • Improves generated metadata, parameter schemas, and operation-level security declarations.
  • Adds request and controller coverage for representations, aliases, discovery, and caching.

Confidence Score: 4/5

The unsupported query-string authentication contract should be corrected before merging so generated clients do not fail when accessing private user statistics.

Five newly annotated operations advertise ApiKeyAuth, but their shared controller path accepts API keys only from the Authorization Bearer header, causing conforming clients that choose the query scheme to receive authorization or lookup failures.

Files Needing Attention: spec/requests/api/v1/stats_spec.rb, swagger/v1/swagger.yaml

Important Files Changed

Filename Overview
app/controllers/openapi_controller.rb Serves the committed public specification as memoized JSON or YAML with public caching and cross-origin access.
config/routes.rb Adds exact canonical and alias routes for both OpenAPI representations without conflicting with the later API namespace.
spec/requests/api/v1/stats_spec.rb Adds optional-auth declarations to five operations, but incorrectly advertises query-string API keys that their controller does not consume.
swagger/v1/swagger.yaml Publishes the generated discovery and security metadata, including the same unsupported ApiKeyAuth alternatives on five stats operations.
test/controllers/openapi_controller_test.rb Covers formats, aliases, public access, cache/CORS headers, discovery metadata, robots directives, and the production server declaration.
Prompt To Fix All With AI
### Issue 1
spec/requests/api/v1/stats_spec.rb:93
**Query API key is unsupported**

When a generated client selects `ApiKeyAuth` for one of these five stats operations, it sends `?api_key=...`, but `StatsController#set_user` accepts API keys only from the Bearer header. The query key is ignored, causing private-user requests to return 403 or `my` lookups to return 404 despite following the published authentication contract; remove `ApiKeyAuth` from these declarations or update the shared authentication path to accept query keys.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "enhance openapi docs" | Re-trigger Greptile

get('Get user heartbeat spans') do
tags 'Stats'
description 'Returns heartbeat spans for a user, useful for visualizations. Accessible anonymously when the target user has public stats lookup enabled; otherwise the requester must be the user (authenticated via the User API Key).'
security [ {}, { Bearer: [] }, { ApiKeyAuth: [] } ]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Query API key is unsupported

When a generated client selects ApiKeyAuth for one of these five stats operations, it sends ?api_key=..., but StatsController#set_user accepts API keys only from the Bearer header. The query key is ignored, causing private-user requests to return 403 or my lookups to return 404 despite following the published authentication contract; remove ApiKeyAuth from these declarations or update the shared authentication path to accept query keys.

Prompt To Fix With AI
This is a comment left during a code review.
Path: spec/requests/api/v1/stats_spec.rb
Line: 93

Comment:
**Query API key is unsupported**

When a generated client selects `ApiKeyAuth` for one of these five stats operations, it sends `?api_key=...`, but `StatsController#set_user` accepts API keys only from the Bearer header. The query key is ignored, causing private-user requests to return 403 or `my` lookups to return 404 despite following the published authentication contract; remove `ApiKeyAuth` from these declarations or update the shared authentication path to accept query keys.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

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