Skip to content

Fix issue #16: OpenAPI response body type#18

Merged
sheepla merged 3 commits intomasterfrom
fix/issue-16-openapi-response-body
May 2, 2026
Merged

Fix issue #16: OpenAPI response body type#18
sheepla merged 3 commits intomasterfrom
fix/issue-16-openapi-response-body

Conversation

@sheepla
Copy link
Copy Markdown
Owner

@sheepla sheepla commented May 2, 2026


Open in Devin Review

Summary by CodeRabbit

  • Bug Fixes

    • OpenAPI generation now unwraps response wrapper types so the documented JSON schemas show the actual response body type (removes spurious wrapper references).
  • New Features

    • Endpoints explicitly declare appropriate success status codes (e.g., 201 Created, 204 No Content) reflected in generated docs.
    • OpenAPI endpoint is registered and exposed for the application.
  • Tests

    • New integration and example tests validate OpenAPI schemas and empty-response behavior.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 2, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 99faaa8e-6d36-4250-99db-9dcda5b1c841

📥 Commits

Reviewing files that changed from the base of the PR and between f3fc197 and ef44744.

📒 Files selected for processing (10)
  • src/AxisEndpoints/IEndpointConfiguration.cs
  • src/AxisEndpoints/Internal/EndpointRegistry.cs
  • tests/AxisEndpoints.Example.Tests/AxisEndpoints.Example.Tests.csproj
  • tests/AxisEndpoints.Example.Tests/ExampleWebApplicationFactory.cs
  • tests/AxisEndpoints.Example.Tests/OpenApiTests.cs
  • tests/AxisEndpoints.Example/Features/Users/Create/CreateUserEndpoint.cs
  • tests/AxisEndpoints.Example/Features/Users/Delete/DeleteUserEndpoint.cs
  • tests/AxisEndpoints.Example/Features/Users/ImportFromCsv/ImportFromCsvEndpoint.cs
  • tests/AxisEndpoints.Tests/Integration/EndpointIntegrationTests.cs
  • tests/AxisEndpoints.Tests/Integration/TestEndpoints.cs
✅ Files skipped from review due to trivial changes (3)
  • tests/AxisEndpoints.Example.Tests/AxisEndpoints.Example.Tests.csproj
  • tests/AxisEndpoints.Example/Features/Users/Create/CreateUserEndpoint.cs
  • src/AxisEndpoints/IEndpointConfiguration.cs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/AxisEndpoints/Internal/EndpointRegistry.cs

📝 Walkthrough

Walkthrough

ApplyMetadata now unwraps Response to the body type when auto-registering Produces(...) and treats EmptyResponse as no-body; tests and test factories add OpenAPI registration and assertions; language-service cache files updated to reflect added source files and analyzer/features for OpenAPI.

Changes

OpenAPI Response Type Unwrapping & Tests

200 behavior and guidance for IResult/ProducesSuccess overrides.
Layer / File(s) Summary
Data Shape / Docstring
src/AxisEndpoints/IEndpointConfiguration.cs
XML docs expanded to explain inferred Response
Core Implementation
src/AxisEndpoints/Internal/EndpointRegistry.cs
ApplyMetadata now uses GetOpenApiResponseType(Type) to unwrap Response<TBody> for OpenAPI metadata, updates IResult-skipping check to use the unwrapped type, and delegates body/no-body registration to new RegisterProduces (treats EmptyResponse as no-body).
Test Project Wiring
tests/AxisEndpoints.Tests/AxisEndpoints.Tests.csproj, tests/AxisEndpoints.Example.Tests/AxisEndpoints.Example.Tests.csproj
Added PackageReference to Microsoft.AspNetCore.OpenApi v10.0.0.
Test App Setup
tests/AxisEndpoints.Tests/Integration/TestWebApplicationFactory.cs, tests/AxisEndpoints.Example.Tests/ExampleWebApplicationFactory.cs
Factories call builder.Services.AddOpenApi() and _app.MapOpenApi() during initialization.
Endpoint Config Updates
tests/AxisEndpoints.Example/Features/Users/Create/CreateUserEndpoint.cs, .../Delete/DeleteUserEndpoint.cs, .../ImportFromCsv/ImportFromCsvEndpoint.cs, tests/AxisEndpoints.Tests/Integration/TestEndpoints.cs
Endpoints now declare explicit success responses (e.g., ProducesSuccess<UserResponse>(Created), ProducesSuccess<EmptyResponse>(NoContent)); added CreatedHelloEndpoint returning Response<HelloResponse> with Created status.
Integration Tests / Validation
tests/AxisEndpoints.Tests/Integration/EndpointIntegrationTests.cs, tests/AxisEndpoints.Example.Tests/OpenApiTests.cs
New tests assert OpenAPI v1 JSON uses the unwrapped body schema refs (e.g., #/components/schemas/HelloResponse, UserResponse, HealthResponse) and that empty responses are not registered as JSON bodies (no ResponseOfEmptyResponse / EmptyResponse schemas).

Language-service Cache Updates (independent)

Layer / File(s) Summary
LSCache - Csv Helper
src/AxisEndpoints.Extensions.CsvHelper/AxisEndpoints.Extensions.CsvHelper.csproj.lscache
Added ICsvBindingErrors.cs to cached sourceFiles.
LSCache - Example Project
tests/AxisEndpoints.Example/AxisEndpoints.Example.csproj.lscache
Removed FindUserByIdRequest.cs from cached sourceFiles.
LSCache - Tests Project
tests/AxisEndpoints.Tests/AxisEndpoints.Tests.csproj.lscache
Expanded command-line features to include Microsoft.AspNetCore.OpenApi.Generated, updated source file list, metadata references, and added an analyzerReferences section listing generator/analyzer DLLs.

Sequence Diagram(s)

sequenceDiagram
    participant EndpointRegistry
    participant OpenApiGenerator
    participant App
    participant TestClient

    Note over EndpointRegistry,OpenApiGenerator: Startup-time metadata registration
    EndpointRegistry->>OpenApiGenerator: RegisterProduces(statusCode, bodyType)
    OpenApiGenerator->>App: Expose /openapi/v1.json
    TestClient->>App: GET /openapi/v1.json
    App->>TestClient: JSON with components.schemas referencing unwrapped body types
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I unwrapped the carrot of response delight,
Schemas now sparkle in OpenAPI light.
No empty wrappers hiding the treat,
Clients can munch on the body meat. 🥕✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed) and handling EmptyResponse appropriately.
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix issue #16: OpenAPI response body type' directly relates to the main changes in the PR, which focus on correcting how OpenAPI schemas are generated for response body types by unwrapping Response
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/issue-16-openapi-response-body

Review rate limit: 9/10 reviews remaining, refill in 6 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 2 additional findings.

Open in Devin Review

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/AxisEndpoints/Internal/EndpointRegistry.cs (1)

472-505: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Handle EmptyResponse before auto-registering Produces.

ResponseExecutor turns Response<EmptyResponse> into a status-only result, but this path now advertises EmptyResponse as a JSON payload. Please skip Produces(200, ...) for no-body responses so the OpenAPI contract matches runtime behavior.

Suggested adjustment
-            if (!isIResult)
+            if (!isIResult && openApiResponseType != typeof(EmptyResponse))
             {
                 routeBuilder.Produces(200, openApiResponseType);
             }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/AxisEndpoints/Internal/EndpointRegistry.cs` around lines 472 - 505, The
auto-registration should skip no-body responses: update the logic that uses
GetOpenApiResponseType(config.ResponseType) (used before calling
routeBuilder.Produces) to treat Response<EmptyResponse> (or EmptyResponse
returned directly) as a no-body case and not call routeBuilder.Produces(200,
...); specifically, after computing openApiResponseType (via
GetOpenApiResponseType) check for EmptyResponse (e.g., openApiResponseType ==
typeof(EmptyResponse) ||
typeof(EmptyResponse).IsAssignableFrom(openApiResponseType)) and bail out of the
Produces(200, ...) registration when true so the OpenAPI contract matches
ResponseExecutor’s status-only behavior; leave the ExtraProducesEntries loop
unchanged.
🧹 Nitpick comments (1)
tests/AxisEndpoints.Tests/Integration/EndpointIntegrationTests.cs (1)

74-86: ⚡ Quick win

Add a regression for the no-body response path.

This test only covers Response<HelloResponse>. Please add a case for Response<EmptyResponse> / NoContent as well, since that is the branch most likely to regress with the new unwrapping logic.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/AxisEndpoints.Tests/Integration/EndpointIntegrationTests.cs` around
lines 74 - 86, The test OpenApi_UsesResponseBodyTypeInsteadOfResponseWrapper
only asserts unwrapping for Response<HelloResponse>; add a second assertion or a
new test that covers the no-body path (Response<EmptyResponse> / NoContent) by
calling _client.GetFromJsonAsync<JsonObject>("/openapi/v1.json") and verifying
the /hello endpoint (or the endpoint that returns EmptyResponse) does not emit a
body schema (or uses the correct no-content representation) and that
components.schemas does not contain a ResponseOfEmptyResponse entry; reference
the existing test pattern (document, schema lookup via
document["paths"]?["/hello"]?["get"]?["responses"]?["204" or
"200"]?["content"]?) and mirror the FluentAssertions checks used in
OpenApi_UsesResponseBodyTypeInsteadOfResponseWrapper to validate the no-body
branch.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/AxisEndpoints/Internal/EndpointRegistry.cs`:
- Around line 472-505: The auto-registration should skip no-body responses:
update the logic that uses GetOpenApiResponseType(config.ResponseType) (used
before calling routeBuilder.Produces) to treat Response<EmptyResponse> (or
EmptyResponse returned directly) as a no-body case and not call
routeBuilder.Produces(200, ...); specifically, after computing
openApiResponseType (via GetOpenApiResponseType) check for EmptyResponse (e.g.,
openApiResponseType == typeof(EmptyResponse) ||
typeof(EmptyResponse).IsAssignableFrom(openApiResponseType)) and bail out of the
Produces(200, ...) registration when true so the OpenAPI contract matches
ResponseExecutor’s status-only behavior; leave the ExtraProducesEntries loop
unchanged.

---

Nitpick comments:
In `@tests/AxisEndpoints.Tests/Integration/EndpointIntegrationTests.cs`:
- Around line 74-86: The test
OpenApi_UsesResponseBodyTypeInsteadOfResponseWrapper only asserts unwrapping for
Response<HelloResponse>; add a second assertion or a new test that covers the
no-body path (Response<EmptyResponse> / NoContent) by calling
_client.GetFromJsonAsync<JsonObject>("/openapi/v1.json") and verifying the
/hello endpoint (or the endpoint that returns EmptyResponse) does not emit a
body schema (or uses the correct no-content representation) and that
components.schemas does not contain a ResponseOfEmptyResponse entry; reference
the existing test pattern (document, schema lookup via
document["paths"]?["/hello"]?["get"]?["responses"]?["204" or
"200"]?["content"]?) and mirror the FluentAssertions checks used in
OpenApi_UsesResponseBodyTypeInsteadOfResponseWrapper to validate the no-body
branch.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 16f180e5-70a0-4de7-b54e-89877476ca86

📥 Commits

Reviewing files that changed from the base of the PR and between 134c6a2 and f3fc197.

📒 Files selected for processing (7)
  • src/AxisEndpoints.Extensions.CsvHelper/AxisEndpoints.Extensions.CsvHelper.csproj.lscache
  • src/AxisEndpoints/Internal/EndpointRegistry.cs
  • tests/AxisEndpoints.Example/AxisEndpoints.Example.csproj.lscache
  • tests/AxisEndpoints.Tests/AxisEndpoints.Tests.csproj
  • tests/AxisEndpoints.Tests/AxisEndpoints.Tests.csproj.lscache
  • tests/AxisEndpoints.Tests/Integration/EndpointIntegrationTests.cs
  • tests/AxisEndpoints.Tests/Integration/TestWebApplicationFactory.cs
💤 Files with no reviewable changes (1)
  • tests/AxisEndpoints.Example/AxisEndpoints.Example.csproj.lscache

@sheepla sheepla merged commit 5fe1ac9 into master May 2, 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