fix(openapi): unit-returning handlers compile and document an empty body (closes #62) - #69
Merged
Merged
Conversation
…ody (closes #62) Two problems with handlers that return nothing. `#[api]` on a handler with no return type did not compile at all: the `ReturnType::Default` branch generated `( () as ::gotcha::Responsible)`, a cast to a *trait*, which is E0782. So an ordinary "returns nothing" handler could not be annotated. The existing `no-args-handler` test only covered no *arguments* — its handler returns `String` — so this path was never exercised. `()` also documented as `{"type": "void"}`, which is not one of the permitted OpenAPI types, so the generated document was invalid and client generators would reject it. - The codegen now emits `<() as Responsible>::response()`. - `Schematic::empty_body()` (default `false`, `true` for `()`) lets the blanket `Responsible` impl document the unit type as a response with **no content**. - The documented status is `200`, matching what axum actually sends: `impl IntoResponse for ()` defers to `Body::empty()` and `http::Response::new` defaults to `StatusCode::OK`. It is not a `204` — a handler wanting that returns `StatusCode::NO_CONTENT` explicitly. - `Json<()>` is deliberately unaffected: it really does send `null` with a 200, so it keeps its JSON response — but `()`'s schema is now an empty schema rather than the invalid `"void"`. The pass test asserts the documented status against `().into_response().status()` itself, so the document cannot drift away from the runtime behaviour. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Kilerd
force-pushed
the
fix/unit-return-handlers
branch
from
August 1, 2026 12:45
eba722d to
9627188
Compare
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.
Closes #62. Two problems with handlers that return nothing.
1.
#[api]on a handler with no return type didn't compileThe
ReturnType::Defaultbranch generated( () as ::gotcha::Responsible)— a cast to a trait. So an ordinary "returns nothing" handler (aDELETE, say) could not be annotated at all. The existingno-args-handlertest only covers no arguments; its handler returnsString, so this path was never exercised.Now emits
<() as Responsible>::response().2.
()documented as"type": "void"— not a valid OpenAPI type{"200":{"content":{"application/json":{"schema":{"type":"void"}}}}}voidisn't among the permitted values, so the document was invalid and client generators reject it. A newSchematic::empty_body()(defaultfalse,truefor()) lets the blanketResponsibleimpl document the unit type as a response with no content.Which status?
200, not204Worth stating explicitly, since
204 No Contentis the intuitive guess. axum sends200with an empty body:http::Response::newdefaults toStatusCode::OK, and there is noNO_CONTENTanywhere in axum-core's response module. Documenting204would have recreated exactly the doc-vs-reality mismatch this PR is fixing. A handler that wants204returnsStatusCode::NO_CONTENTexplicitly.The test pins this down by asserting the documented status against
().into_response().status()itself, so if axum ever changes, the test fails rather than the document silently lying.Json<()>is deliberately left aloneWrapping the unit in
Jsonis genuinely different: it really does sendnullwith a200. That keeps its JSON response; only the schema changed, from the invalid"void"to an empty schema.Test
tests/pass/openapi/unit_responses.rscovers all three shapes — no return type, explicit-> (), andJson<()>— asserting the response carries no content and that"void"appears nowhere.Verified locally:
gotcha(openapi) +gotcha_coresuites,cargo clippy --all-features --workspace,cargo fmt --check.🤖 Generated with Claude Code