docs(api-reference): type organization response envelopes in OpenAPI spec - #254
Conversation
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
There was a problem hiding this comment.
Pull request overview
Updates the Organizations standalone OpenAPI spec (docs/api-reference/organizations-openapi.json) to replace previously untyped “envelope” response descriptions with concrete JSON response schemas, enabling typed API reference rendering and downstream SDK/codegen typing.
Changes:
- Adds new component schemas for response envelopes and related DTOs (e.g., group budgets, payment methods, wallets, pagination meta).
- Updates multiple success responses to include
application/jsonresponse bodies that$refthe new envelope schemas. - Adjusts some existing response schema references to point to the new envelope DTOs.
Comments suppressed due to low confidence (2)
docs/api-reference/organizations-openapi.json:7082
OrganizationWalletTokenBalanceDto.formattedis declared astype: objectbut the description/example indicate it’s a human-readable string balance. This should bestring(nullable) to avoid incorrect client types.
"formatted": {
"type": "object",
"description": "Human-readable balance (null if the read failed)",
"example": "1.5",
"nullable": true
}
docs/api-reference/organizations-openapi.json:7190
OrganizationWalletResponseDto.labelis typed asobject, but both the example and the request DTOs (CreateOrganizationWalletDto/UpdateOrganizationWalletDto) definelabelas a string. This should bestring(nullable) so response typing matches the rest of the spec.
"label": {
"type": "object",
"example": "Treasury",
"nullable": true
},
r-marques
left a comment
There was a problem hiding this comment.
🤖 Automated PR review — 🔴 Blocked
Reviewed origin/main...HEAD (1 file, +770/−27) with the code-reviewer agent, plus a source-fidelity pass diffing every added schema against the backend implementation in nvm-monorepo and the mirrored PR nevermined-io/nvm-monorepo#2532. Every finding below was re-verified directly against the source and @redocly/cli lint before posting.
One blocker: a response is typed with a schema the API does not return. Everything else is small, and the underlying work is careful — 19 of the 20 added schemas are faithful transcriptions of the source DTOs.
🔴 Blockers (1)
-
POST /organizations/{orgId}/groups/{groupId}/members(201) is typed with a body the API never returns —docs/api-reference/organizations-openapi.json:2897— (code-reviewer + fidelity pass, confidence high)The response is
$ref: GroupResponseEnvelopeDto, i.e.{ success, group: GroupResponseDto }. The handler returns a membership, not a group:// nvm-monorepo apps/api/src/organizations/groups/groups.controller.ts (addMember) return { success: true, membership: { id: m.id, groupId: m.groupId, orgMemberId: m.orgMemberId, isActive: m.isActive }, }
There is no
groupkey in that response. The previous prose ("Member added to group") declared no shape, so this schema is invented rather than transcribed — the one place in the PR where that happens. Published as-is, the API reference tells integrators to read a field that will always beundefined.Note this originates upstream: nvm-monorepo#2532 applies the same wrong
@ApiResponse({ type: GroupResponseEnvelopeDto })toaddMember, so the fix belongs in both PRs. It needs aGroupMemberResponseDto({ id, groupId, orgMemberId, isActive }) plus an envelope keyedmembership.
🟡 Should fix (3)
-
GET /organizations/{orgId}/groups/{groupId}— the description promisesmembers, the new schema drops it —:2730(description) /:2734($ref) — (confidence high)The description says
groupis "a GroupResponseDto plusmembers: GroupMemberResponseDto[]", butGroupResponseEnvelopeDtorefs a plainGroupResponseDto, which has nomembers. The backend sides with the description:// groups.service.ts async getGroup(orgId, groupId): Promise<GroupResponseDto & { members: GroupMemberResponseDto[] }>
A rendered schema outranks prose for readers, so this endpoint is now under-documented — it was previously ambiguous, and is now confidently wrong about an omission. Needs its own envelope (
allOf, or aGroupWithMembersDto). Related:GroupMemberResponseDtois named in the prose but defined nowhere in the spec. -
Three new properties declare
type: objectbut carry string examples — (confidence high)Field Line Declared Real type OrganizationWalletTokenBalanceDto.atomic:7071type: object, example"1500000"string | nullOrganizationWalletTokenBalanceDto.formatted:7077type: object, example"1.5"string | nullOrganizationWalletResponseDto.label:7186type: object, example"Treasury"string | nullMintlify will render these as
object. Confirmed by lint delta:@redocly/cli lintemits 8no-invalid-schema-exampleson base and 11 on head — the delta is exactly these three.Root cause is the SWC
design:type = Objectfootgun that nvm-monorepo's own CLAUDE.md documents: those@ApiPropertydecorators omittype: String. Corroboration from inside this same PR —GroupPaymentMethodResponseDto.brand/last4/alias/orgIdcome out correctly astype: stringprecisely because their source decorators do passtype: String. Fix totype: string+nullable: truehere, and in the source decorators, or the next re-export reintroduces it. -
Merge ordering: nvm-monorepo#2532 is still OPEN, not merged — (confidence high)
The docs describe the shape #2532 annotates. That PR's own DTO file states "Swagger metadata only — the wire shape is unchanged", so the
{ success, … }envelope is already today's runtime behaviour and merging the docs first does not misdescribe the deployed API. Flagging it only because the blocker above must be fixed on both sides — if the docs fix lands alone, #2532 will re-introduce the wrong shape at the source.
💡 Good to have (3)
- Coverage is now ~65% and the gap is domain-shaped. After this PR, 57 of 84
2xxresponses carry a schema; 27 do not, of which 2 are legitimate204s → 25 real bodies still prose-only: billing (7), webhooks (8), org members (5), customers (2), invitations (2),GET /organizations/user-info/{userId}(1). Groups/budgets/wallets now render full schemas while billing/webhooks render bare prose, which reads as inconsistency rather than staged work. Several of the untyped descriptions already spell the shape out inline ({ canceled, cancelAt, currentPeriodEnd },{ items, total }), so they are the cheapest follow-up. - All
4xxresponses remain untyped, leavingOrganizationsErrorResponseDto(:6641) an orphan schema — Redocly flags it underno-unused-components. Pre-existing, but this was the natural moment to wire it up. (CreateOrganizationDtois the other pre-existing orphan.) - Durability of the hand-edit. This file is a manual paste of the API's own
buildOrganizationsOpenApiDocument()output, so a future re-paste would silently drop all 20 hand-written schemas. #2532 landing is what makes that safe — worth a note in the repo's CLAUDE.md thatorganizations-openapi.jsonis hand-maintained, unlike its generated neighbours.
✅ Strengths
- The two changed
$refs are a genuine bug fix, not churn.POST …/groups201 (:2616) andPATCH …/groups/{groupId}200 (:2791) previously pointed straight atGroupResponseDtowhile the API returns the{ success, group }envelope — this corrects documentation that was actively misleading. - Structurally clean. Valid OpenAPI
3.0.0; all 80$refs resolve; no duplicate keys;nullable: trueis correct 3.0 syntax; no schema-levelexamples. Adds 3 lint warnings and 0 errors. - Field-level fidelity is high — this is transcription, not guesswork, which is exactly why the one invented schema stands out. Verified against source:
GroupBudgetResponseDtomatches all 10 fields including theintervalenum["month","year","one_shot"]andstatus["Active","Exhausted"];GroupPaymentMethodResponseDtogets the nullable set exactly right;OrganizationWalletResponseDtocorrectly omitslabelfromrequiredbecause the source uses@ApiPropertyOptional;OrganizationWalletWithdrawResponseDto.txHashis nullable, matchingPromise<{ userOpHash: string; txHash: string | null }>. - Good factoring.
OrganizationsSuccessResponseDtois reused across 9 bare-{success}endpoints,PaginationMetaDtois extracted rather than inlined, and the…ResponseEnvelopeDto(singular) /…ListResponseDto(collection) convention is applied consistently across all 20 additions. - Editing this file by hand is correct. Verified, not assumed: the docs repo's only workflow is path-filtered to
skills/nevermined-payments/**, and nvm-monorepo's two docs-sync workflows writedocs/development-guide/*only (sync-api-changelog-docs.ymlexplicitly notes its target is "deliberately NOT underdocs/api-reference/*"). No bot has ever touched this file. The CLAUDE.md "don't modify api-reference" rule does not bite here.
Comment-only review — no approval or change-request recorded, and nothing in this PR was modified.
Addendum — independent second passA second verification pass (mechanical diff of all 20 added schemas against 1. The fix for the blocker is cheaper than it looked — the DTO already exists. 2. Nothing in CI would have caught the blocker. No test in either repo pins the 3. Correction to my "the CLAUDE.md rule does not bite here". That was right about the mechanical risk — verified, no workflow in either repo writes this file, so the hand-edit will not be clobbered. But it understated a real documentation conflict: this repo's Relatedly, Unchanged: the blocker stands, and it needs fixing in both this PR and #2532. |
9dc4756 to
d6843c1
Compare
|
Thanks — all points addressed and pushed (spec regenerated from the corrected DTOs; mirrors nvm-monorepo#2532): 🔴 r-marques blocker — member-add typed with a body the API never returns Copilot — Out of scope (pre-existing, untouched by this response-typing change): the same nullable- |
…spec
Regenerates the standalone Organizations OpenAPI spec so the groups,
budgets, payment-method and wallet endpoints carry typed `{ success, … }`
response schemas instead of prose-only descriptions.
Adds 24 component schemas (16 response envelopes + the item DTOs and
transitive types their responses reference, which were previously pruned
because the endpoints returned untyped bodies) and wires all 27 success
responses to their envelope via `$ref`.
- Member-add is a membership envelope (`{ success, membership }`).
- GET group returns a `GroupWithMembersDto` (group + typed `members[]`).
- Nullable string fields (wallet label, token atomic/formatted balance,
group description) render as `string` not `object`.
Mirrors nvm-monorepo #2532.
d6843c1 to
ff7d417
Compare
…#255) Follow-up to #254. Five fields in the Organizations OpenAPI spec rendered as `type: object` instead of their scalar type — the SWC decorator-metadata gotcha on `T | null` DTO fields, fixed in the source in nvm-monorepo #2532: - TierCatalogRowDto.stripeLookupKey -> string, nullable - InvitationResponseDto.name + PublicInvitationInfoDto.name -> string, nullable - Create/UpdateGroupBudgetDto.maxTransactions -> number, nullable Codegen/SDK consumers now get the correct scalar types.
What
Regenerates the standalone Organizations OpenAPI spec
(
docs/api-reference/organizations-openapi.json) so the groups, budgets,payment-method and wallet endpoints describe their real
{ success, <item(s)> }response bodies with typed schemas — previously theycarried only a prose
description: 'Envelope `{ success, budget }`'and noresponse schema, so the API reference and SDK codegen saw an untyped body.
Mirrors the backend change in nevermined-io/nvm-monorepo#2532.
Changes
(
GroupResponseEnvelopeDto,GroupBudgetListResponseDto,OrganizationWalletWithdrawResponseDto,OrganizationsSuccessResponseDto, …)plus the item DTOs and transitive types they
$ref(
GroupBudgetResponseDto,OrganizationWalletBalancesDto,OrganizationWalletTokenBalanceDto,PaginationMetaDto, …), which had beenpruned from the spec because the endpoints returned untyped bodies.
$reftheir envelope schema.(verified a no-op re-serialization is byte-identical to the committed file);
all
$refs resolve; no schema-levelexamples(OpenAPI 3.0 clean).Test plan
$refs resolve