Skip to content

feat(api): Export API reference data as @sentry/api/docs - #150

Merged
BYK merged 3 commits into
mainfrom
feat/api-docs-export
Nov 13, 2026
Merged

BYK merged 3 commits into
mainfrom
feat/api-docs-export

Conversation

@sentry-junior

@sentry-junior sentry-junior Bot commented Nov 13, 2026

Copy link
Copy Markdown
Contributor

Stacked on #149. Ported from getsentry/sentry#130538, per @BYK's request there: get the docs aligned here first, then move @sentry/api into getsentry/sentry.

This adds the data sentry-docs needs to build the API reference from the @sentry/api version it pins, so it no longer has to read openapi-derefed.json from a pinned commit of this repository. The sentry-docs adapter is getsentry/sentry-docs#20679.

Changes from the sentry version

2.0.0 (#148) made every path relative to the API base path and trimmed server URLs to their origin. The export now follows the same contract:

  • operation paths are relative, such as /organizations/, the same as @sentry/api/operations;
  • the base path ships as API_BASE_PATH (/api/0) and as apiBasePath in extractDocs() output, so a page builds the full path as ${API_BASE_PATH}${operation.path};
  • per-operation servers are origins.

extractDocs() applies splitApiBasePath to a copy of the spec it gets, so the published data and a preview of a local spec have the same shape. It accepts both the current spec and one that declares the base path in servers.

sentry-docs#20679 needs a follow-up for this: its adapter has to prepend API_BASE_PATH to paths, like sentry-docs#20787 does for 2.0.0. I'll push that once this shape is settled.

What it adds

  • scripts/generate-docs.mjs, next to the operations generator. It runs lib/docs-catalog.mjs extractDocs(spec) on the original openapi-derefed.json and emits src/docs.ts. That file holds the data as a JSON string literal, so tsc doesn't infer a type for 3.7 MB of data. It ships as @sentry/api/docs (dist/docs.js plus .d.ts).
  • Shape (lib/docs-types.ts):
    • apiBasePath / API_BASE_PATH.
    • tags: name, description, sidebarName (x-sidebar-name) and displayDescription (x-display-description).
    • operations, in spec order: operationId, method and relative path, with summary and description copied as written. Also tags, deprecated, experimental (x-sentry-experimental), server origins, security requirements, and parameters (path-level merged with operation overrides) with in, required, description, experimental and schema. The request body comes from its first content type (content type, required, schema, example), and every response has its status, description, content type, schema and example/examples.
  • extractDocs is exported too, so sentry-docs' OPENAPI_LOCAL_PATH preview of an unreleased local spec goes through the same projection as the published data.
  • lib/http-methods.mjs holds the HTTP method set that both catalogs use.

The export's shape is now a semver contract

sentry-docs, and anything else that imports @sentry/api/docs, depends on these field names and types. Removing or renaming a field, or changing its type, is a major release. Adding fields is a minor release. The README says so.

Size

Measured with npm pack --dry-run from clean builds of #149 and this branch, using the spec in this repository:

tgz unpacked files
#149 3,385,825 B 35,812,862 B 80
this PR 3,828,867 B 39,660,930 B 86
change +443 KB (+13%) +3.85 MB (+11%) +6

Almost all of it is dist/docs.js (3,840,561 B). It's a separate entry point, so @sentry/api and @sentry/api/client users like toolkit don't load it unless they import ./docs. They only pay for the download.

Tests

  • test/docs.test.ts:
    • A fixture test pins the exact output shape. Its spec declares /api/0 in servers and an operation server override under it, so the test also covers the relative paths, apiBasePath and origin-only servers. It also covers path-level parameter overrides, experimental flags, multiple content types, responses without content, named examples and security.
    • Drift tests compare the published @sentry/api/docs with openapi-derefed.json:
      • the export equals extractDocs(spec), and API_BASE_PATH is /api/0;
      • tag and operation order matches the spec, with API_BASE_PATH plus each relative path equal to the spec's path;
      • for every operation, the text, parameters, request schema and example, and response schemas and examples match the spec directly.
  • test/package.test.ts: the packed-tarball smoke test imports @sentry/api/docs.

pnpm build, pnpm typecheck and pnpm test pass locally (54 files, 679 tests).

No UI change here. The sentry-docs PR carries the API reference screenshots.

Merge order

#149, this PR, the normal release of an @sentry/api version with ./docs, then getsentry/sentry-docs#20679 with its API_BASE_PATH follow-up. That PR's dependency bump is its last step.

Co-Authored-By: BYK 126780+BYK@users.noreply.github.com

--

View Session [Sentry]

Comment thread scripts/generate-docs.mjs Resolved
Base automatically changed from fix/api-list-page-offset to main November 13, 2026 14:32
Add a docs generator next to the operations catalog. It projects the
dereferenced spec onto what an API reference page shows: tags, full
parameters, the request body's first content type, responses with
schemas and examples, security and servers. It ships as the ./docs
export with types, plus extractDocs() to build the same data from an
unreleased spec.

As in the client and the operation catalog since 2.0.0, paths are
relative to the API base path, which the export carries as
API_BASE_PATH, and server overrides keep only their origin.

Tests pin the shape with a fixture and check the published export
against the spec it was built from, so the two can't drift.

Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
@BYK
BYK force-pushed the feat/api-docs-export branch from 811d00e to db4e4c1 Compare November 13, 2026 14:32
Comment thread README.md Resolved
…e strings

generate-docs now builds docs.ts from ts.factory nodes and writes it
through a new writeSource helper that prints with the TypeScript printer.

A local oxlint plugin adds sentry-api/no-typescript-source-strings, which
reports .ts files written from strings, templates, concatenation or
.join(), and string patches through replaceOnce, in build.mjs, scripts/
and lib/. CI runs it as pnpm lint. The generators that predate the rule
are listed in .oxlintrc.json until they move to the printer.
API_BASE_PATH comes from the spec's server URL, so naming its current value would go stale if the server changes it.
@BYK
BYK merged commit 7871887 into main Nov 13, 2026
11 checks passed
@BYK
BYK deleted the feat/api-docs-export branch November 13, 2026 15:25
BYK added a commit that referenced this pull request Nov 13, 2026
Main has been red since the spec sync from getsentry/sentry#131065
landed (36d0d11). That sync made spec paths relative to the server URL's
`/api/0`. Two tests still look up or compare full `/api/0` paths, so
Build fails and no `@sentry/api` release goes out until this lands.

- `test/descriptions.test.ts` (from #142):

`spec.paths["/api/0/organizations/{organization_id_or_slug}/dashboards/"]`
→ `spec.paths["/organizations/{organization_id_or_slug}/dashboards/"]`
- `test/docs.test.ts` (from #150, written against the old spec),
comparing the export's paths with the spec's:
`` `${operation.method} ${API_BASE_PATH}${operation.path}` `` → ``
`${operation.method} ${operation.path}` ``

No other test reads `spec.paths` by a full `/api/0` key. The remaining
`/api/0` strings in tests are request URLs, which are still correct.

Checks: `pnpm build`, `pnpm typecheck`, `pnpm test` (681 passed) and
`check-script-modes.sh` pass.

<!-- junior-request-attribution:start -->
via @BYK.
<!-- junior-request-attribution:end -->

<!-- junior-session-footer:start -->
<!-- junior-conversation-id:agent%3A640c5343d03e547097aa9b8a711daaf5 -->

--

[View
Session](https://junior-prod.sentry.dev/conversations/agent%3A640c5343d03e547097aa9b8a711daaf5)
[[Sentry]](https://sentry.sentry.io/explore/conversations/agent%3A640c5343d03e547097aa9b8a711daaf5/?project=4510944073809921)

<!-- junior-session-footer:end -->

Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com>
Co-authored-by: BYK <126780+BYK@users.noreply.github.com>
BYK added a commit to getsentry/sentry-docs that referenced this pull request Nov 13, 2026
The API reference now comes from the `@sentry/api` version this repo
pins (`2.3.0`), through its `./docs` export
(getsentry/sentry-api-schema#150). It no longer fetches
`openapi-derefed.json` from a pinned getsentry/sentry-api-schema commit.
The rendered pages don't change.

## Changes

- **`src/build/resolveOpenAPI.ts`** reads `{tags, operations}` from
`@sentry/api/docs` and maps them to the `APICategory`/`API` shapes the
pages already use.
- `OPENAPI_LOCAL_PATH` still works in development. It runs a local `make
build-api-docs` spec through the package's `extractDocs()`, so previews
take the same path as production.
  - `src/build/open-api/types.ts` is gone; the package types replace it.
- Optional query parameters now carry `required: false` instead of no
key. The pages check `!!param.required`, so they render the same.
- **`scripts/tsconfig.json`** maps `@sentry/api/docs` to `dist/docs.js`
for the Algolia script. `tsx` resolves through Node's CJS resolver, and
the export only has an `import` condition.
- **Bump workflow:** `bump-api-schema-sha.yml` is now **Bump
@sentry/api**. It keeps its file name, so existing dispatches still
reach it.
- It runs hourly and on `workflow_dispatch`, with a concurrency group so
the two can't push the same branch.
- `scripts/bump-sentry-api.sh` (POSIX `sh`) reads the latest version
from npm, pins it exactly in `package.json` and the lockfile, then opens
and merges the PR with the same app token as before. A pre-commit hook
runs shellcheck on it.
  - Dependabot here only does security updates, so it doesn't fit.
- **`pnpm-workspace.yaml`** only holds settings (no `packages` list). It
puts `@sentry/api` in `minimumReleaseAgeExclude`, so the hourly bump can
still pin a release minutes after it ships once pnpm applies a
release-age default. It does nothing on the current `pnpm@10.30.0`: the
lockfile, dependency tree, `package.json` pnpm settings and root `pnpm
add` behave as before.
- **`develop-docs/backend/api/public.mdx`:** the build process section
describes the new flow, and the `openapi-diff` text matches
getsentry/sentry#130541: a changelog that never fails, plus a separate
RPC breaking-change job. Hold that part until that PR merges.

## Screenshots

These `next dev` screenshots are 1400px wide. Before is the current
reader on the same spec through `OPENAPI_LOCAL_PATH`; after is this PR
reading `@sentry/api/docs`. The images are pixel-identical except for
the Next.js dev badge, so two pairs have the same URL.

**Create a New Team**

| Before | After |
|---|---|
|
![before](https://junior-prod.sentry.dev/public/artifacts/707914ce-aa28-4ed5-a9a7-f6a6b7cc9a1e.png)
|
![after](https://junior-prod.sentry.dev/public/artifacts/3b1116af-bf1b-49ea-b6f7-4c94b9e53976.png)
|

**Create a Custom Inbound Filter** (experimental, with a body)

| Before | After |
|---|---|
|
![before](https://junior-prod.sentry.dev/public/artifacts/682fdbb5-f4bc-4c61-be92-4ded51d63568.png)
|
![after](https://junior-prod.sentry.dev/public/artifacts/682fdbb5-f4bc-4c61-be92-4ded51d63568.png)
|

**List Your Organizations**

| Before | After |
|---|---|
|
![before](https://junior-prod.sentry.dev/public/artifacts/69f1d6af-e058-40cb-b457-bb5a14d90af3.png)
|
![after](https://junior-prod.sentry.dev/public/artifacts/69f1d6af-e058-40cb-b457-bb5a14d90af3.png)
|

## After merging

sentry-api-schema's "Cascade to sentry-docs" dispatch is no longer
needed.

<!-- junior-request-attribution:start -->
via @BYK.
<!-- junior-request-attribution:end -->

<!-- junior-session-footer:start -->
<!-- junior-conversation-id:agent%3A69da19b385017e68b7f9eace56e9477f -->

--

[View
Session](https://junior-prod.sentry.dev/conversations/agent%3A69da19b385017e68b7f9eace56e9477f)
[[Sentry]](https://sentry.sentry.io/explore/conversations/agent%3A69da19b385017e68b7f9eace56e9477f/?project=4510944073809921)

<!-- junior-session-footer:end -->

---------

Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com>
Co-authored-by: BYK <126780+BYK@users.noreply.github.com>
sentry-junior Bot added a commit to getsentry/sentry that referenced this pull request Nov 14, 2026
Brings static/packages/api level with getsentry/sentry-api-schema main
(2.3.1):

- @sentry/api/docs exports the API reference data (getsentry/sentry-api-schema#150), with the
  no-typescript-source-strings lint rule, which the api client CI job
  now runs.
- listPage keeps per_page stable across offset cursors (getsentry/sentry-api-schema#149).
- ApiPermissionError carries the scopes from a 403 insufficient_scope
  challenge (getsentry/sentry-api-schema#146).
- Union fields and annotated single-member allOf fields keep their own
  descriptions.

The version moves to 2.3.1, so craft's first api@ release bumps from
sentry-api-schema's latest npm version. The release check no longer cuts
a patch for API ownership stats alone: the asset stays on each release
for ad-hoc use, but nothing reads it on a schedule.

Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
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