Repository navigation
docs(api): declare error status codes in API specs - #4668
Merged
Merged
Conversation
Operations listed their error status codes only in their description and declared a single default response, so API references, Postman and the generated clients showed "default" instead of the actual codes. Each code from an operation's "error returns" list is now a response of its own, with the reason from the list as its description and a shared ProblemDetails body. Its example shows the title and status the node returns, such as "IssueVC failed" and 412, with the reason as detail; the node puts its own error message there, as the detail description now says. The lists are removed from the descriptions, as the responses carry them now. Generic 500 lines are dropped: every operation can return 500, which stays covered by the default response. Its description says so and refers to RFC 9457, which obsoletes RFC 7807. As all operations share the default response, its example illustrates a 500 Internal Server Error with a placeholder for the operation name, which its description points out. The Discovery server spec used that response for the explicit 400 of registerPresentation as well, so that 400 now has a response of its own, with the reason from its list and a matching example. The lists were checked against each API's error handling, and corrected where they were wrong or incomplete: - Auth v2 never returns 503, as an unreachable authorizer results in 500 or 502. requestUserAccessToken and requestOpenid4VCICredentialIssuance don't check credentials, so they can't return 412 either. Those entries are dropped. - listTrusted and listUntrusted return an empty list for an unknown credential type, not 404. - requestOpenid4VCICredentialIssuance returns 404 for an unknown subject. - Every Network operation returns 400 when did:nuts support is not configured. - retrieveAccessToken, getCredentialsInWallet, getContactInformation and updateContactInformation had no list; they get the codes their handlers return. ProblemDetails is a shared type in ssi_types.yaml. The codegen configs map that file to its generated Go package with import-mapping, so all API packages use the same ProblemDetails type. The ssiTypes test becomes an external test package, as it imports the VCR API, which now imports ssiTypes. getCompoundServices had its list in the summary, which API references show as the title. Response codes in the Auth v1 and DID Manager specs are now quoted, as OpenAPI requires. The generated clients now parse a declared error into its own field, such as ApplicationproblemJSON404, instead of ApplicationproblemJSONDefault; the browser e2e helpers that read the default field now check for a missing 200 response instead. The new detail description appears as a comment in every generated package, including the Discovery server API, which shares the default response. vdr/api/v2/generated.go also picks up a description change in its spec that was never regenerated.
The error body schema was defined three times: as ProblemDetails in ssi_types.yaml, inline in error_response.yaml, and inline in the 400 of the Discovery server's registerPresentation. Both copies now refer to ProblemDetails. The Discovery server codegen config gets the same import-mapping as the other configs. The merge script passes error_response.yaml through paste(), so its reference points into the combined document like the references in the specs. Tools resolve that reference relative to error_response.yaml, so the comment saying they don't follow it is removed. A typedef template override in the common types config generates ProblemDetails as a type alias of the struct that oapi-codegen generated inline for each error body before. All API packages share it, and code that uses the anonymous struct type of the error fields keeps compiling. The generated code shrinks by almost 2,000 lines.
JorisHeadease
marked this pull request as ready for review
November 3, 2026 15:35
JorisHeadease
requested review from
Dirklectisch,
gerardsn,
reinkrul,
stevenvegt and
woutslakhorst
as code owners
November 3, 2026 15:35
Member
|
Is this actually better in terms of maintainability? This leads to lots of duplication... |
# Conflicts: # didman/api/v1/generated.go # docs/_static/didman/v1.yaml # docs/_static/vdr/v2.yaml
Each error response that an operation declares for a status code repeated its reason as the example's detail, and the reference to ProblemDetails. The description now has an anchor that the example's detail refers to, the first of these responses in each spec anchors the schema reference that the others reuse, and the example takes one line. Most responses shrink from ten lines to six. The specs parse to the same content, so the API reference, Postman and the generated code are unchanged.
Contributor
25 new issues
|
Contributor
Author
|
It's a trade-off between maintainability vs. usability of the docs. Without theses examples, users see the following as error: Which is... far from ideal. OpenAPI 3.0 doesn't really offer a way to prevent the duplication afaik. I did make the blocks shorter with YAML anchors and aliases: six lines instead of ten, and the example no longer repeats the reason. As for the maintainability, I don't think we have to "maintain" the error codes too much? Let me know what you think about the trade-off @reinkrul, can always remove the examples |
reinkrul
approved these changes
Nov 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Follow-up to this question in #4660: the API reference showed
defaultinstead of the actual error codes, because most operations declared their errors only asdefault, with the codes as text in their description ("error returns: …"). This declares the codes in the specs, so Scalar, Postman and the generated clients show them.Preview: https://jorisheadease.github.io/nuts-node-docs-preview/pages/integrating/api.html
Changes in the specs
ProblemDetailsbody, new incommon/ssi_types.yaml. The lists are removed from the descriptions.IssueVC failedand 412. The example's detail is the reason; in an actual response it is the node's error message, as thedetaildescription now says.detailis an alias of the description, and each spec anchors the reference toProblemDetailsonce. Most responses take six lines instead of ten.default. Its description says so and refers to RFC 9457, which obsoletes RFC 7807. Its example illustrates a 500 with a placeholder for the operation name, as all operations share it. Its body refers to the sameProblemDetails, so the schema is defined once.registerPresentationas well. That 400 now has its own description and example, and refers toProblemDetailstoo.error_response.yamlthroughpaste()like the specs, so its reference points into the combined document.Corrections
The lists were checked against each API's error handling:
requestUserAccessTokenandrequestOpenid4VCICredentialIssuancedon't check credentials, so they can't return 412 either.listTrustedandlistUntrustedreturn an empty list for an unknown credential type, not 404.requestOpenid4VCICredentialIssuancereturns 404 for an unknown subject.retrieveAccessToken,getCredentialsInWallet,getContactInformationandupdateContactInformationhad no list; they now declare the codes their handlers return.Generated code
common/ssi_types.yamlto its Go package withimport-mapping, so all API packages use the sameProblemDetailstype.api/ssi_types_test.gobecomes an external test package, as it imports the VCR API, which now importsapi.typedef.tmploverride incommon_ssi_types.yamlgeneratesProblemDetailsas a type alias of the struct that oapi-codegen generated inline for each error body before, so code that uses that struct type keeps compiling.ApplicationproblemJSON404, instead ofApplicationproblemJSONDefault. The JSON is unchanged. The browser e2e helpers that read the default field now check for a missing 200 response instead.vdr/api/v2/generated.goalso picks up a description change in its spec that was never regenerated on master.Verified
go build ./...,go vetfor the API packages and for./e2e-tests/browser/...with-tags e2e_tests, and the fullgo test ./...pass.Backports to V6.2 and V5.4 will follow after merge.