Skip to content

Add OpenAPI docs for Sourcebot public API#996

Merged
brendan-kellam merged 6 commits intosourcebot-dev:mainfrom
KonradStanski:konrad/public-openapi
Mar 12, 2026
Merged

Add OpenAPI docs for Sourcebot public API#996
brendan-kellam merged 6 commits intosourcebot-dev:mainfrom
KonradStanski:konrad/public-openapi

Conversation

@KonradStanski
Copy link
Contributor

@KonradStanski KonradStanski commented Mar 12, 2026

Generate and publish OpenAPI docs for the public search, repo, and file-browsing endpoints, add Mintlify integration, and serve the generated spec at /api/openapi.json.

Note: /api/stream_search remains modeled as text/event-stream in OpenAPI. OpenAPI 3.0 does not provide a first-class way to describe SSE frames as a typed stream of JSON events.

Fixes #101

Summary by CodeRabbit

  • Documentation

    • Added a comprehensive OpenAPI spec and published API Reference pages documenting search, repos, file browsing, and version endpoints.
  • New Features

    • Public API documentation is now generated and included with releases for external integrations.
  • Chores

    • Added generation script, CI step to produce the spec, and included the spec in the release image.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 12, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds generated OpenAPI docs and generation tooling for Sourcebot's public REST surface; centralizes git-related Zod schemas; exposes the spec via a new API route; integrates generation into CI/release and copies the spec into the Docker image.

Changes

Cohort / File(s) Summary
Docs & OpenAPI artifact
docs/api-reference/sourcebot-public.openapi.json, docs/docs.json, docs/docs/api-reference/overview.mdx, CHANGELOG.md
Adds generated OpenAPI v3 spec, docs navigation and overview page, and updates changelog.
OpenAPI generation tooling
packages/web/tools/generateOpenApi.ts, packages/web/package.json, package.json (root)
Adds OpenAPI generation script and workspace/npm scripts; adds @asteasolutions/zod-to-openapi devDependency and root script to invoke generation.
OpenAPI runtime modules
packages/web/src/openapi/publicApiDocument.ts, packages/web/src/openapi/publicApiSchemas.ts
Introduces OpenAPI registry, schema wrappers, and document builder exposing createPublicOpenApiDocument(version).
Schema consolidation (git feature)
packages/web/src/features/git/schemas.ts, packages/web/src/features/git/getFileSourceApi.ts, packages/web/src/features/git/getFilesApi.ts, packages/web/src/features/git/getTreeApi.ts
Moves/re-exports getTree/getFiles/fileSource request/response Zod schemas into a centralized schemas.ts; callers updated to re-export/use shared schemas.
Serve spec & API route updates
packages/web/src/app/api/(server)/openapi.json/route.ts, packages/web/src/app/api/(server)/source/route.ts, packages/backend/src/api.ts
Adds route serving the OpenAPI JSON; source route now validates with shared fileSourceRequestSchema; minor formatting change in backend API file.
CI / Release / Docker
.github/workflows/release-prod.yml, Dockerfile
Runs OpenAPI generation in release workflow and stages the generated spec for commit; copies generated spec into the container image.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor CI as CI/Release Job
  participant Gen as generateOpenApi.ts
  participant FS as Repository FS
  participant Git as Git Commit Step
  participant Runner as Web App (server)
  participant Client as Browser / Doc Consumer

  CI->>Gen: run yarn openapi:generate
  Gen->>FS: create docs/api-reference/...json
  FS-->>Gen: write success
  CI->>Git: stage & commit generated spec
  Git-->>CI: commit success
  Runner->>FS: read docs/api-reference/...json (openapi.json route)
  Client->>Runner: GET /api/openapi.json
  Runner-->>Client: application/vnd.oai.openapi+json document
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • chore(web): Reorganize git apis #831: Reorganized git APIs and types in packages/web/src/features/git referenced by the new centralized schemas.
  • V4 #311: Modifies the same server API surface (packages/web/src/app/api/(server)/source/route.ts) and related request validation wiring.

Suggested labels

sourcebot-team

Suggested reviewers

  • msukkari
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding OpenAPI documentation for the public API, which is the primary objective of this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Generate and publish OpenAPI docs for the public search, repo, and file-browsing endpoints, add Mintlify integration, and serve the generated spec at /api/openapi.json.

Note: /api/stream_search remains modeled as text/event-stream in OpenAPI. OpenAPI 3.0 does not provide a first-class way to describe SSE frames as a typed stream of JSON events.
@KonradStanski KonradStanski force-pushed the konrad/public-openapi branch from 872c4d8 to 17a49a9 Compare March 12, 2026 07:31
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (3)
packages/web/src/openapi/publicApiDocument.ts (2)

232-238: Consider adding additional server entries for production/cloud environments.

The servers array only includes the local development server. For a public API reference, consumers might benefit from seeing the production URL pattern or a placeholder indicating where to substitute their deployment URL.

📝 Suggested enhancement
         servers: [
             {
                 url: 'http://localhost:3000',
                 description: 'Local development web app',
             },
+            {
+                url: 'https://{your-domain}',
+                description: 'Your Sourcebot deployment',
+            },
         ],
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/web/src/openapi/publicApiDocument.ts` around lines 232 - 238, The
OpenAPI document's servers array currently only lists the local entry; update
the servers array in publicApiDocument to include additional entries for
production/cloud (e.g., a production URL and a templated/placeholder like
{baseUrl}) so consumers see expected deployment endpoints. Modify the servers
array where it's defined (the variable/object containing servers and tags:
[searchTag, reposTag, filesTag, miscTag]) to add a production URL and/or a URL
template with a description and optional variables (e.g., baseUrl) so clients
can substitute their environment; ensure descriptions clearly label development
vs production entries.

24-46: Consider adding a comment explaining the manual schema definition.

The manual SchemaObject definitions for the file tree node are necessary because zod-to-openapi doesn't handle recursive/self-referential schemas well. A brief inline comment would help future maintainers understand why these aren't derived from Zod schemas like the other definitions.

📝 Suggested documentation
+// Manual OpenAPI schema for the recursive file tree node structure.
+// zod-to-openapi doesn't support z.lazy() / self-referential schemas,
+// so we define this directly as a SchemaObject with $ref.
 const publicFileTreeNodeSchema: SchemaObject = {
     type: 'object',
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/web/src/openapi/publicApiDocument.ts` around lines 24 - 46, Add a
short inline comment above the manual SchemaObject definitions explaining why
they are hand-written: publicFileTreeNodeSchema (recursive/self-referential
children) and publicGetTreeResponseSchema cannot be generated from the Zod types
because zod-to-openapi does not handle recursive schemas; state that this is
intentional and link or note zod-to-openapi's limitation to aid future
maintainers.
packages/web/src/openapi/publicApiSchemas.ts (1)

18-23: The current Zod extension pattern is safe and reasonable.

The guard at lines 18-23 is an appropriate approach since extendZodWithOpenApi is only called in this file. While moving the extension to a dedicated initialization module could be a minor structural improvement, it is not necessary for correctness and the current implementation prevents accidental double-extension within the module's execution context.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/web/src/openapi/publicApiSchemas.ts` around lines 18 - 23, Keep the
current safe pattern: leave the module-scoped guard (hasExtendedZod) and the
call to extendZodWithOpenApi(z) as-is so the Zod extension runs exactly once
within this module; ensure you don't remove hasExtendedZod or introduce another
extension call elsewhere (refer to hasExtendedZod, extendZodWithOpenApi, and z)
— if you prefer a refactor later, move the same guarded logic into a dedicated
initialization module, but no functional change is needed now.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/api-reference/sourcebot-public.openapi.json`:
- Around line 8-13: The OpenAPI document currently exposes a local-only server
("servers" -> url "http://localhost:3000"), which will be embedded into
generated clients; update the "servers" entry in the API spec by either removing
the entire "servers" array or replacing the localhost URL with a deploy-safe
default (e.g., a production or placeholder base URL such as
"https://api.example.com" or a templated variable) so generated clients/tooling
don't default to localhost; ensure you modify the "servers" array in the
top-level OpenAPI object to reflect this change.
- Around line 444-448: The description of the PublicStreamSearchSse type
references a missing schema PublicStreamedSearchEvent in components.schemas;
either add a proper schema definition for PublicStreamedSearchEvent (and any
sub-event variants like "chunk"/"done" you expect) into the source OpenAPI model
so components.schemas.PublicStreamedSearchEvent exists and describes the SSE
JSON frame shape, and ensure the generator/template picks up that schema, or
remove/replace the dangling name from PublicStreamSearchSse.description in the
source document so it does not reference a non-existent schema; update the
source generator templates if necessary so generated docs include
components.schemas.PublicStreamedSearchEvent.

In `@docs/docs/api-reference/overview.mdx`:
- Around line 6-8: Rewrite the opening paragraph so it leads with the runtime
spec URL "/api/openapi.json" (instead of the static docs artifact
"/api-reference/sourcebot-public.openapi.json"), use second person ("you") and
present tense, and keep sentences short and direct; specifically update the
lines that currently say "Sourcebot exposes a public REST API..." and the
sentence mentioning the Mintlify-rendered file so they start by telling the
reader to use "/api/openapi.json" on their instance, and state that the endpoint
reference is generated from Zod schemas/OpenAPI registry and rendered by
Mintlify in plain, actionable language.

---

Nitpick comments:
In `@packages/web/src/openapi/publicApiDocument.ts`:
- Around line 232-238: The OpenAPI document's servers array currently only lists
the local entry; update the servers array in publicApiDocument to include
additional entries for production/cloud (e.g., a production URL and a
templated/placeholder like {baseUrl}) so consumers see expected deployment
endpoints. Modify the servers array where it's defined (the variable/object
containing servers and tags: [searchTag, reposTag, filesTag, miscTag]) to add a
production URL and/or a URL template with a description and optional variables
(e.g., baseUrl) so clients can substitute their environment; ensure descriptions
clearly label development vs production entries.
- Around line 24-46: Add a short inline comment above the manual SchemaObject
definitions explaining why they are hand-written: publicFileTreeNodeSchema
(recursive/self-referential children) and publicGetTreeResponseSchema cannot be
generated from the Zod types because zod-to-openapi does not handle recursive
schemas; state that this is intentional and link or note zod-to-openapi's
limitation to aid future maintainers.

In `@packages/web/src/openapi/publicApiSchemas.ts`:
- Around line 18-23: Keep the current safe pattern: leave the module-scoped
guard (hasExtendedZod) and the call to extendZodWithOpenApi(z) as-is so the Zod
extension runs exactly once within this module; ensure you don't remove
hasExtendedZod or introduce another extension call elsewhere (refer to
hasExtendedZod, extendZodWithOpenApi, and z) — if you prefer a refactor later,
move the same guarded logic into a dedicated initialization module, but no
functional change is needed now.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2c747ce7-d9a5-4fe6-acc2-6c9ca546f4ed

📥 Commits

Reviewing files that changed from the base of the PR and between 1ce1ec8 and 17a49a9.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (15)
  • docs/api-reference/sourcebot-public.openapi.json
  • docs/docs.json
  • docs/docs/api-reference/overview.mdx
  • package.json
  • packages/backend/src/api.ts
  • packages/web/package.json
  • packages/web/src/app/api/(server)/openapi.json/route.ts
  • packages/web/src/app/api/(server)/source/route.ts
  • packages/web/src/features/git/getFileSourceApi.ts
  • packages/web/src/features/git/getFilesApi.ts
  • packages/web/src/features/git/getTreeApi.ts
  • packages/web/src/features/git/schemas.ts
  • packages/web/src/openapi/publicApiDocument.ts
  • packages/web/src/openapi/publicApiSchemas.ts
  • packages/web/tools/generateOpenApi.ts

Remove the localhost servers entry, clarify the SSE stream description, point docs readers at /api/openapi.json, add the changelog entry, and update the lockfile metadata.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@CHANGELOG.md`:
- Around line 10-13: Update the changelog entry that currently reads "Added
generated OpenAPI documentation for the public search, repo, and file browsing
API surface. [`#101`]" to use the correct pull request id "[`#996`]" and move this
line from the "### Changed" section into the "### Added" section; ensure the
entry ends with " [`#996`]" and that the "### Added" header contains this line
while removing it from "### Changed".

In `@packages/web/src/openapi/publicApiDocument.ts`:
- Around line 225-239: The OpenAPI document currently lacks security
definitions; after generator.generateDocument(...) add a securitySchemes entry
under document.components (e.g., document.components.securitySchemes = {
bearerAuth: { type: 'http', scheme: 'bearer', bearerFormat: 'JWT' } }) and set a
global document.security (e.g., document.security = [{ bearerAuth: [] }]) so
clients know to send credentials; keep per-operation overrides (clear security
on truly unauthenticated endpoints) rather than leaving endpoints anonymous. Use
the existing symbols document, document.components, and
generator.generateDocument to locate where to add these fields and add/merge
them alongside the existing schemas logic that sets document.components.schemas
and PublicFileTreeNode.

In `@packages/web/src/openapi/publicApiSchemas.ts`:
- Around line 41-46: publicVersionResponseSchema currently pins the example for
the version field to a hard-coded string which drifts from the actual build;
update the z.object for publicVersionResponseSchema so the version example is
either removed or set dynamically (e.g., use the app/build version constant)
instead of the literal 'v4.15.2' — locate publicVersionResponseSchema and the
nested version field in publicApiSchemas.ts and replace the static example with
a dynamic value pulled from your build/version export or drop the example
entirely.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dafa7a08-28f4-4294-8e43-f8d4e07c8a8c

📥 Commits

Reviewing files that changed from the base of the PR and between 17a49a9 and 16a5ca0.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (5)
  • CHANGELOG.md
  • docs/api-reference/sourcebot-public.openapi.json
  • docs/docs/api-reference/overview.mdx
  • packages/web/src/openapi/publicApiDocument.ts
  • packages/web/src/openapi/publicApiSchemas.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/docs/api-reference/overview.mdx

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/release-prod.yml:
- Around line 134-138: The workflow runs "Install dependencies" and "Generate
OpenAPI docs" while the repo remote has the write-scoped GitHub App token
persisted; change the checkout/credential handling so these steps run without
persisted credentials: set the actions/checkout used before the "Install
dependencies" and "Generate OpenAPI docs" steps to persist-credentials: false
(or use a read-only checkout action), and only configure/inject the write-scoped
app token immediately before the step that performs the git push (e.g., the step
that calls git push or "Release" logic). Ensure the checkout used for the push
step has persist-credentials true or re-checkout with the token injected so only
the final push runs with write access.

In `@docs/api-reference/sourcebot-public.openapi.json`:
- Around line 141-148: Change discrete numeric schema types from "number" to
"integer" for fields representing counts/IDs/positions—specifically update
"byteOffset", "lineNumber", and "column" (and other discrete fields like IDs,
status codes, pagination/count fields) to use "type": "integer" and add
"format": "int32" or "int64" where appropriate in the OpenAPI generator output;
update the generator/template that emits these properties so all occurrences
(e.g., other count/id/position schemas referenced in the spec) are emitted as
integer types rather than floating-point numbers.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7980c617-35d4-4c3e-897c-c8c8f9dde470

📥 Commits

Reviewing files that changed from the base of the PR and between 1937304 and 30cf3a5.

📒 Files selected for processing (2)
  • .github/workflows/release-prod.yml
  • docs/api-reference/sourcebot-public.openapi.json

brendan-kellam
brendan-kellam previously approved these changes Mar 12, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/web/src/app/api/(server)/openapi.json/route.ts (1)

18-26: Add explicit GET query validation for this API route.

This GET handler does not validate query params with a Zod schema + queryParamsSchemaValidationError. Even if no params are expected, validate an explicit empty schema to enforce contract consistency.

As per coding guidelines API route handlers should validate query parameters using Zod schemas with queryParamsSchemaValidationError for GET requests.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/web/src/app/api/`(server)/openapi.json/route.ts around lines 18 -
26, Add explicit query validation at the top of the exported GET handler: create
a Zod empty object schema (e.g., const querySchema = z.object({})) and validate
the incoming request query against it before calling loadOpenApiDocument(); on
validation failure return the existing queryParamsSchemaValidationError with the
Zod error. Import z from 'zod' and queryParamsSchemaValidationError, perform the
parse/parseAsync on the request's query/searchParams inside the async function
exported as GET (the handler passed to apiHandler), and only proceed to call
loadOpenApiDocument() and return Response.json(...) when validation succeeds.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/web/src/app/api/`(server)/openapi.json/route.ts:
- Around line 8-15: Resolve the OpenAPI file path from process.cwd() into the
container's /app docs (use path.join(process.cwd(), 'docs', 'api-reference',
'sourcebot-public.openapi.json') instead of '../../docs/...') when constructing
openApiPath, and change the ENOENT catch branch in the JSON read/parse block
(the JSON.parse(await fs.readFile(...)) try/catch around openApiPath) to not
silently swallow the error: either rethrow or throw a new explicit error (e.g.,
"OpenAPI document not found") so the handler returns an error/404 instead of a
successful empty response; apply the same path and ENOENT handling fix to the
analogous block referenced at lines 19-25.

---

Nitpick comments:
In `@packages/web/src/app/api/`(server)/openapi.json/route.ts:
- Around line 18-26: Add explicit query validation at the top of the exported
GET handler: create a Zod empty object schema (e.g., const querySchema =
z.object({})) and validate the incoming request query against it before calling
loadOpenApiDocument(); on validation failure return the existing
queryParamsSchemaValidationError with the Zod error. Import z from 'zod' and
queryParamsSchemaValidationError, perform the parse/parseAsync on the request's
query/searchParams inside the async function exported as GET (the handler passed
to apiHandler), and only proceed to call loadOpenApiDocument() and return
Response.json(...) when validation succeeds.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b9b71832-ee78-4799-9314-a0c36d030598

📥 Commits

Reviewing files that changed from the base of the PR and between 30cf3a5 and 5e16c10.

📒 Files selected for processing (2)
  • Dockerfile
  • packages/web/src/app/api/(server)/openapi.json/route.ts

@brendan-kellam brendan-kellam merged commit d649710 into sourcebot-dev:main Mar 12, 2026
5 checks passed
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.

[FR] Sourcebot REST API support

2 participants