Uh oh!
There was an error while loading. Please reload this page.
feat(api): describe response schemas in the OpenAPI document - #38
Merged
Conversation
Every endpoint returned IResult, which the schema generator cannot read, so the document described five paths and no shapes. Declaring the responses turns it into a contract a client can be generated from. Two facts the generator still cannot infer are supplied by a schema transformer: optional scalars are omitted rather than sent as null, so a nullable property is not required; and an enum reaches the wire as a string, so its members are listed from the enum a property declares.
A consumer generating a client cannot run this service to obtain the document, so it is committed. Build-time generation is not an option: the generator runs the composition root, which validates options on start and so needs a refresh key to produce a document. The script boots the built assembly instead and reads the document over HTTP. servers is stripped, or the artifact would record whichever port the generating run used.
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 freeto 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.
The frontend wants to generate its client from this service's contract rather than hand-writing it. It could not: the document described five paths and no shapes at all.
Every endpoint returns
Task<IResult>, which is opaque to the schema generator, and nothing declared a response type. A generated client would have given every endpointunknown.What changed
Responses are declared.
.Produces<T>()and.ProducesProblem(...)on each route, with the statuses each endpoint's code paths can actually produce —GetProjectgets 404,TriggerRefreshgets 401,/diagnosticsgets neither, and the four cacheable reads get 304.This is deliberately not a
TypedResultsrefactor.Loom.Resultscategories map throughToHttpResult()at one point, and "a slice never writes a status code" is a rule here;TypedResultswould have pushed status decisions back into handlers. The cost is honest:Produces<T>is a claim the compiler does not check.Schema ids are qualified by operation. Every slice names its response type
Response, andcomponents.schemasis a flat namespace, so all five collapsed onto one schema — the site's.CreateSchemaReferenceIdnow yieldsGetSiteResponse,ListProjectsResponseand so on.Two facts the generator cannot infer are supplied by a schema transformer.
required, contradictingDefaultIgnoreCondition = WhenWritingNulland this repo's own rule. A consumer would have typedname: string | nullwhen the key is simply absent.status,role,type,kind,source,severityandoutcomegenerated as barestring. They now list their members, taken from the enum each property declares via[WireEnum(typeof(...))]— next to the field rather than in a central table, so nothing has to be kept in sync by hand. Relation names come fromRelationVocabularyitself.Per-property naming is load-bearing:
SiteLinkType.GitHubisgithubunderWire.Lowerbutgit-hubunderWire.Hyphenate, so one rule for all of them would be wrong.Wiregained aLower(string)overload so the transformer does not lowercase inline.The document is committed, and CI fails when it drifts. A consumer cannot run this service to obtain it.
scripts/openapi.shregenerates it; CI regenerates and diffs, so a wire type cannot change without the contract moving with it.Build-time generation via
Microsoft.Extensions.ApiDescription.Serverwas tried and rejected: the generator runs the composition root, which validates options on start, sodotnet buildbegan failing on a clean checkout without aRefreshKey.serversis stripped from the artifact — it records whichever port the generating run used. Output verified byte-identical across two different ports, so the drift check cannot fire spuriously.Result
Verification
dotnet build0 warnings underTreatWarningsAsErrors,dotnet format --verify-no-changesclean, 364/364 tests pass includingArchitectureTests. The wire records stayedinternal.The drift check was tested by adding a field to
SiteLinkViewand confirming CI's comparison goes red, then reverting. Its first version used a baregit diff --exit-code, which passes silently while the file is untracked; it now runsgit add --intent-to-addfirst, so a deleted or untracked document fails too.