docs(API): Document how to verify a public API migration (#37048)

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
Uddish Verma
2026-09-01 13:03:37 +00:00
committed by GitHub
co-authored by Claude Opus 5
parent d88eee888c
commit de09565056
2 changed files with 46 additions and 2 deletions
+11 -1
View File
@@ -132,7 +132,15 @@ model; reuse only what applies. Decorators, all from `@n8n/decorators`:
on `@ApiResponse` stripping to hide fields.
- Treat the output DTO as an allowlist. Re-check nested relations, ownership
fields, tokens, and encrypted values.
- Make input DTOs strict so unknown/partial fields aren't silently accepted.
- An output DTO restricts which fields you return, not which values they may hold.
The registry parses the handler's return value against it, so a value the schema
rejects becomes a `500`. Keep the schema loose enough for anything an existing
row may contain.
- Build the response from the relations the route loaded, not from the entity type.
TypeORM relations are opt-in, so two routes over the same entity can return
different shapes.
- Make input DTOs strict so unknown/partial fields aren't silently accepted:
`Z.class(shape, { strict: true })`.
- Secrets: never return a real secret; use the resource's sentinel/placeholder
(or omit). See [Updates and write-only secrets](reference.md#updates-and-write-only-secrets).
@@ -186,3 +194,5 @@ existing tests.
- [Errors](reference.md#errors)
- [Testing matrix](reference.md#testing-matrix)
- [Migrating legacy EOV endpoints](reference.md#migrating-legacy-eov-endpoints)
- [Verifying a migration](reference.md#verifying-a-migration)
- [CI and merging](reference.md#ci-and-merging)
+35 -1
View File
@@ -100,7 +100,8 @@ scope, RBAC denial. Add whichever apply, matching the nearest existing tests:
`PUT` with the exact sentinel keeps the secret; any other value replaces it;
the sentinel is never persisted as a real secret.
- Migration: path, method, status codes, scope, and response contract are
unchanged.
unchanged. Tests alone cannot show this — see
[Verifying a migration](#verifying-a-migration).
## Migrating legacy EOV endpoints
@@ -147,3 +148,36 @@ not templates.
— never extend them).
- For complex legacy-only, multipart, or non-standard endpoints, study the
nearest existing handler first.
- Keep each field in its original position when you extract a request shape shared
by two routes, and destructure out the ones a route doesn't take. The generator
emits properties in shape order, so a moved field rewrites the `*.generated.yml`
of a route the PR wasn't changing.
## Verifying a migration
Tests are written against the new code, so they can't show that the old behavior
survived. These checks can:
- Diff live responses against master. Run the route on an instance per branch and
compare status, body, and error message for the same requests. Reading the old
YAML beside the new Zod schema doesn't find the differences.
- Check whether a field is absent or `null`. `activeVersion` omitted is not the
same response as `activeVersion: null`; use a conditional spread to omit it.
- Check query-param coercion at the edges (`""`, `"0"`, `"false"`, absent). A Zod
DTO and the old validator don't coerce identically.
- Request a route the PR didn't migrate. A shared DTO change can stop the spec
bundle compiling at startup, which turns every legacy route into a `500` without
failing a test.
## CI and merging
Two failures that a migration hits outside the code itself:
- Merge master in before merging. A generator change on master leaves every
branch's committed `*.generated.yml` stale, and `generated-spec-drift.test.ts`
then fails only on the merge commit, so the PR itself stays green and
`MERGEABLE`. `gh pr checks` hides `merge_group` runs; look for the run on
`gh-readonly-queue/master/pr-<number>-<sha>`.
- Ask a maintainer for a `/size-limit-override` early. Generated YAML counts
toward the 1,000-line PR size limit, so a single-route migration can exceed it
on generator output alone.