document-api-endpoint

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Document & Type a Sentry API Endpoint

为Sentry API端点编写文档并定义类型

Add or fix OpenAPI docs for a Sentry endpoint with drf-spectacular. Full reference is at https://develop.sentry.dev/backend/api/public/, the most useful section to you will be https://develop.sentry.dev/backend/api/public/#5-method-decorator. This skill captures the non-obvious lessons on top of it. Most of the work is making the declared schema match what the endpoint actually returns. Before documenting, identify which endpoint class serves the route and what it does; the MCP tool that calls it is usually the fastest way to confirm its behavior. Promoting a PRIVATE/EXPERIMENTAL endpoint to PUBLIC is one application (see below).

Workflow

工作流程

  1. Class-level
    @extend_schema(tags=[...])
    — use the closest existing
    OPENAPI_TAGS
    entry.
  2. Method-level
    @extend_schema(operation_id=..., parameters=[...], responses={...}, examples=...)
    .
  3. Reuse
    src/sentry/apidocs/parameters.py
    and
    examples/*.py
    ; ensure
    owner = ApiOwner.<TEAM>
    is set.
  4. If a legacy
    api-docs/paths/**/*.json
    covers the path, remove it (see lesson 4).
  5. Validate, then verify against the live endpoint (lesson 1).
  1. 类级别的
    @extend_schema(tags=[...])
    —— 使用最接近的现有
    OPENAPI_TAGS
    条目。
  2. 方法级别的
    @extend_schema(operation_id=..., parameters=[...], responses={...}, examples=...)
  3. 复用
    src/sentry/apidocs/parameters.py
    examples/*.py
    ;确保设置
    owner = ApiOwner.<TEAM>
  4. 如果旧版
    api-docs/paths/**/*.json
    包含该路径,请删除它(见经验4)。
  5. 验证,然后对照在线端点进行确认(经验1)。

Lessons

经验总结

1. Carefully compare what the code does vs declared types

1. 仔细对比代码实际行为与声明的类型

Ideally, hit the live endpoint with a real token and diff the keys and types against your TypedDict. Serializers are sometimes inaccurate. Look out for counts coming back as floats instead of integers, IDs declared
int
emitted as strings, nested types declaring the wrong number of fields. Correct the declared type to match runtime.
bash
curl -s -H "Authorization: Bearer $TOKEN" "https://us.sentry.io/api/0/<endpoint>" | jq 'keys'
理想情况下,使用真实令牌访问在线端点,将返回的键和类型与您的TypedDict进行对比。序列化器有时并不准确。注意返回的计数是浮点数而非整数、声明为
int
的ID以字符串形式返回、嵌套类型声明的字段数量错误等情况。修正声明的类型使其与运行时一致。
bash
curl -s -H "Authorization: Bearer $TOKEN" "https://us.sentry.io/api/0/<endpoint>" | jq 'keys'

2. Reuse the canonical response type

2. 复用标准响应类型

Match the codebase's
XxxResponseOptional(TypedDict, total=False)
mixin (main class declares required fields). Nullable-vs-absent:
T | None
= key always present, value may be null;
NotRequired[T]
= key only set under a condition (e.g. an
expand
query param). Reuse the existing canonical type instead of re-declaring a second or third copy in a
*_types.py
. If there's no clean canonical type to reuse (e.g. a payload proxied from another service like vroom/profiling), type it
dict[str, Any]
rather than inventing a new mirror, and confirm the shape from the owning service's repo, not just the serializer.
匹配代码库中的
XxxResponseOptional(TypedDict, total=False)
混合类(主类声明必填字段)。可空与缺失的区别:
T | None
表示键始终存在,值可能为null;
NotRequired[T]
表示键仅在特定条件下设置(例如
expand
查询参数)。复用现有的标准类型,而非在
*_types.py
中重复声明第二或第三个副本。如果没有清晰的标准类型可复用(例如从vroom/profiling等其他服务代理的负载),则将其类型定义为
dict[str, Any]
,而非创建新的镜像类型,并从所属服务的仓库确认其结构,而不只是依赖序列化器。

3. Infer the type. Avoid
cast
and
# type: ignore

3. 推导类型,避免使用
cast
# type: ignore

When a serializer returns a base type plus extra fields, refactor the producing code so the response type is inferred rather than forced.
当序列化器返回基础类型加额外字段时,重构生成代码,使响应类型可被推导而非强制指定。

4. Legacy doc migration is all-or-nothing per path

4. 旧版文档迁移需针对路径完整处理

Delete the
api-docs/paths/**/*.json
file AND its
$ref
in
api-docs/openapi.json
. drf-spectacular's
APPEND_PATHS
does not merge HTTP methods, so once any method on a path uses
@extend_schema
, all legacy methods on that path vanish — migrate every method on the path in one commit.
删除
api-docs/paths/**/*.json
文件及其在
api-docs/openapi.json
中的
$ref
。drf-spectacular的
APPEND_PATHS
不会合并HTTP方法,因此一旦路径上的任何方法使用
@extend_schema
,该路径上的所有旧版方法都会消失——请在一次提交中迁移该路径上的所有方法。

Promoting to PUBLIC

升级为PUBLIC

Do the workflow above, then on the concrete endpoint only (leave siblings PRIVATE):
  • Bump
    publish_status[<METHOD>]
    PUBLIC
    and set
    owner = ApiOwner.<TEAM>
    .
  • Remove the method from
    API_OWNERSHIP_ALLOWLIST_DONT_MODIFY
    in the same change as the flip.
  • If the endpoint is redundant or being renamed, delete or deprecate the old version in its own change first, then stack the publish on top.
  • Note in the PR if scopes widen (
    event:read
    event:{admin,read,write}
    ) — that's drf-spectacular regenerating from
    permission_classes
    , documentation-only.
The change reaches the
@sentry/api
SDK / MCP only after
sentry-api-schema
regenerates downstream.
完成上述工作流程后,仅针对具体端点(保留同级端点为PRIVATE):
  • publish_status[<METHOD>]
    升级为
    PUBLIC
    并设置
    owner = ApiOwner.<TEAM>
  • 在同一变更中,将该方法从
    API_OWNERSHIP_ALLOWLIST_DONT_MODIFY
    中移除。
  • 如果端点冗余或正在重命名,请先在单独的变更中删除或弃用旧版本,再叠加发布操作。
  • 如果权限范围扩大(例如
    event:read
    event:{admin,read,write}
    ),请在PR中注明——这是drf-spectacular从
    permission_classes
    重新生成的,仅影响文档。
变更需等
sentry-api-schema
在下游重新生成后,才会同步到
@sentry/api
SDK / MCP。

Validate

验证

bash
make build-api-docs
pnpm run validate-api-examples
.venv/bin/pytest -q --reuse-db tests/apidocs/endpoints/<area>/test_<name>.py
.venv/bin/prek run -q --files <changed paths>
bash
make build-api-docs
pnpm run validate-api-examples
.venv/bin/pytest -q --reuse-db tests/apidocs/endpoints/<area>/test_<name>.py
.venv/bin/prek run -q --files <changed paths>