Skip to content

Update GenHTTP to 11.1 and document the API for its consumers - #124

Merged
Kaliumhexacyanoferrat merged 1 commit into
mainfrom
genhttp-11
Oct 17, 2026
Merged

Kaliumhexacyanoferrat merged 1 commit into
mainfrom
genhttp-11

Conversation

@Kaliumhexacyanoferrat

Copy link
Copy Markdown
Collaborator

Updates GenHTTP to 11.1 and uses its new webservice documentation attributes to document /api/v1 for whoever calls it - an agent or a developer writing a client - rather than for whoever maintains it.

What a reader of /api/v1/scalar/ gets now

  • An introduction (Resources/Api/Introduction.md): getting started in three calls (checked against a running server), who may do what with which key, what versions, data and features are, the file format, the limits and where to read them, and how refusals are answered.
  • Tags by concept, not by class, in seven groups shown in Scalar's sidebar (x-tagGroups, set in ApiDocumentation): Getting started, The program, What it keeps, How it is doing, Sharing it, The build agent, Operating the installation.
  • Every operation describes its behavior, not just its purpose. That covers what it changes and what it leaves alone, every way it is refused and why (with the ErrorResponse body), the 201/202/422 answers where those are used, and zip and binary bodies and downloads with their content types and Content-Disposition. The operator's endpoints declare X-Admin-Token with its 401/403. I read the services to write this: key rules, file name rules, the order a change is applied in, what a merge carries over and what it throws away, what switching data off deletes, when previews go offline, and so on.
  • Every model and field is described. The records' <param> comments moved into [Summary] on the parameters, so each field is described once and reaches the schema. XML comments keep only the why for maintainers.
Introduction Errors
introduction errors
A tag An operation
data merge

Kept complete

ApiDocumentationTests reads the served document and fails on:

  • an operation without a summary
  • a parameter, answer, model or field without a description
  • a call below /lambdas/{privateKey} that does not say how an unknown key is answered
  • a tag in no group

It also pins the answers that matter: 201 for what is created, 202 for the agent, 422 with the compiler's diagnostics, zips as zips. CLAUDE.md has the rules under The API description, and the README's API section points to the description.

Other effects of 11.1

  • GenHTTP.Full no longer carries GenHTTP.Testing, so the tests reference it themselves.
  • The export no longer needs ASP.NET Core: its Dockerfile now uses dotnet/runtime:10.0 instead of aspnet. I checked by exporting demo-crud, publishing it (the runtimeconfig.json names only Microsoft.NETCore.App) and running it: it applied its migration and served its page.

Framework issues found (not worked around)

  1. Schema property names don't match the wire format. SchemaManager generates schemas with NewtonsoftJsonSchemaGeneratorSettings and its default naming, so the document says PublicKey while the API answers camelCase publicKey (System.Text.Json, JsonFormat). Requests still work because they are read case-insensitively. A client generated from the spec would mis-read every answer, though, and Scalar's examples show the wrong names. The same root cause lists [JsonIgnore] properties that are never sent (LambdaFile.IsCompiled, IsCode, IsResource, Bytes); the test names these explicitly as known gaps. Repro: any record returned by a webservice and the openapi.json of ApiDescription.Create().
  2. Every reference-type return is documented with a phantom 204. OpenApiExtensions.MightBeNull returns true for any class and ignores nullable annotations, so LambdaResponse Get(...) gets "204 - A response containing no body" next to its 200. NullabilityInfoContext on the return parameter would tell. The phantom only disappears where a success response is declared explicitly; I did not add declarations just to hide it.
  3. The OpenAPI media type check has a doubled prefix. OpenApiConcern matches "application/application/vnd.oai.openapi+json" (and +yaml), so /openapi with Accept: application/vnd.oai.openapi+json answers 400.
  4. The binary schema has no type. GetBinarySchema() produces { "format": "binary" } without "type": "string", which OpenAPI 3.0 requires next to the format.
  5. Inferred 200 responses have an empty description unless the method has [return: Summary]. OpenAPI requires a description. I added [return: Summary] everywhere, which documents the answer anyway.
  6. Not a bug, but worth having: the authentication concerns (ApiKeyConcern and the others) don't implement IDocumentedConcern, so the header and the 401/403 they add are declared by hand on the three operator resources.

Test plan

  • dotnet build with no warnings, dotnet test: 851 passed
  • Looked at Scalar in a browser (screenshots above): sidebar groups, introduction, a tag, an operation with every response
  • Ran the getting-started calls against a local server
  • Exported a demo, published it, and ran it on the plain .NET runtime

🤖 Generated with Claude Code

https://claude.ai/code/session_015kWXmwvMJGrUr1pw9iEBy3

GenHTTP 11.1 lets webservices document themselves ([Summary], [Remarks],
[Response], [RequestBody], [RequestHeader], [ResponseHeader], [Tag]).
The OpenAPI document of /api/v1 is now written with them, for whoever
calls the API rather than for whoever maintains it:

- An introduction (Resources/Api/Introduction.md): getting started,
  who may do what with which key, versions, data and features, the file
  format, limits and where to read them, and how refusals are answered.
- Tags by concept rather than by class, in groups Scalar shows in the
  sidebar (x-tagGroups, ApiDocumentation).
- Every operation says what it does and how it behaves: what it changes
  and leaves alone, every way it is refused and why (with ErrorResponse),
  201/202/422 where those are answered, zip and binary bodies and
  downloads with their content types, the admin token on the operator's
  endpoints. Read off the services, not guessed.
- Every model and field is described; the fields' <param> comments
  moved into [Summary], so they are said once.
- ApiDocumentationTests keep it so: an undocumented operation,
  parameter, answer, model or field fails the build.

11.1 no longer ships GenHTTP.Testing in GenHTTP.Full, so the tests
reference it on their own - and the export no longer needs ASP.NET
Core, so its Dockerfile runs on the plain runtime image.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015kWXmwvMJGrUr1pw9iEBy3
@Kaliumhexacyanoferrat
Kaliumhexacyanoferrat merged commit faaf578 into main Oct 17, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant