Skip to content

Support Minimal API endpoints in offline OpenAPI generation#7874

Draft
Hinton wants to merge 1 commit into
mainfrom
openapi-minimal-api-support
Draft

Support Minimal API endpoints in offline OpenAPI generation#7874
Hinton wants to merge 1 commit into
mainfrom
openapi-minimal-api-support

Conversation

@Hinton

@Hinton Hinton commented Jun 26, 2026

Copy link
Copy Markdown
Member

🎟️ Tracking

📔 Objective

Our current Swagger implementation using Swashbuckle with Startup.cs does not support automatically detecting Minimal Api's. This implements a workaround which creates a custom EndpointDataSource which gets registered earlier and are therefore detected by the Swagger generation CLI.

  • Add Bit.HttpExtensions.StandaloneEndpointDataSource and the AddOpenApiEndpointDataSource registration helper. The offline OpenAPI generator (dotnet swagger tofile) never runs the Configure pipeline where Minimal API endpoints are mapped via UseEndpoints, so it omits them. A single DI-registered EndpointDataSource composes every feature's mapping delegate and is gated to swagger generation only, so it never replaces the runtime composite EndpointDataSource that routing and link generation depend on.
  • Teach SwaggerGenOptionsExt.BuildOperationId and ActionNameOperationFilter to derive the operation ID and action name from the endpoint name set via .WithName(...) when there are no controller/action route values, as is the case for Minimal API endpoints.
  • Guarantee BuildOperationId never returns a null/empty operation ID: a Minimal API endpoint mapped without .WithName() now falls back to a deterministic id derived from the HTTP method and route template. Swashbuckle writes the selector's value straight onto operation.OperationId, so a null/empty id would collapse distinct endpoints together and abort spec generation via CheckDuplicateOperationIdsDocumentFilter.
  • Add unit tests for BuildOperationId (including the route fallback), the ActionNameOperationFilter endpoint-name branch, StandaloneEndpointDataSource composition, and AddOpenApiEndpointDataSource gating/registration.

Example Output

Example output of a minimal API.

    "/access-requests/history": {
      "get": {
        "tags": [
          "AccessRequests"
        ],
        "operationId": "Pam_AccessRequests_GetHistory",
        "responses": {
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponseModel"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponseModel"
                }
              }
            }
          },
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccessRequestDetailsResponseModelListResponseModel"
                }
              }
            }
          }
        },
        "x-action-name": "GetHistory",
        "x-action-name-snake-case": "get_history",
        "x-source-file": "bitwarden_license/src/Commercial.Pam/Api/Endpoints/AccessRequestEndpoints.cs",
        "x-source-line": 20
      }
    },

Extract the PAM-free swagger foundation from the PAM POC so it can land on
main independently.

- Add Bit.HttpExtensions.StandaloneEndpointDataSource and the
  AddOpenApiEndpointDataSource registration helper. The offline OpenAPI
  generator (dotnet swagger tofile) never runs the Configure pipeline where
  Minimal API endpoints are mapped via UseEndpoints, so it omits them. A single
  DI-registered EndpointDataSource composes every feature's mapping delegate and
  is gated to swagger generation only, so it never replaces the runtime
  composite EndpointDataSource that routing and link generation depend on.
- Teach SwaggerGenOptionsExt.BuildOperationId and ActionNameOperationFilter to
  derive the operation ID and action name from the endpoint name set via
  .WithName(...) when there are no controller/action route values, as is the
  case for Minimal API endpoints.
- Guarantee BuildOperationId never returns a null/empty operation ID: a Minimal
  API endpoint mapped without .WithName() now falls back to a deterministic id
  derived from the HTTP method and route template. Swashbuckle writes the
  selector's value straight onto operation.OperationId, so a null/empty id would
  collapse distinct endpoints together and abort spec generation via
  CheckDuplicateOperationIdsDocumentFilter.
- Add unit tests for BuildOperationId (including the route fallback), the
  ActionNameOperationFilter endpoint-name branch, StandaloneEndpointDataSource
  composition, and AddOpenApiEndpointDataSource gating/registration.
@Hinton Hinton requested a review from justindbaur June 26, 2026 15:08
@sonarqubecloud

Copy link
Copy Markdown

@Hinton Hinton added the t:tech-debt Change Type - Tech debt label Jun 26, 2026
@codecov

codecov Bot commented Jun 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.45455% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 61.23%. Comparing base (3a09bca) to head (147bf18).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/SharedWeb/Swagger/SwaggerGenOptionsExt.cs 88.88% 0 Missing and 2 partials ⚠️
src/HttpExtensions/StandaloneEndpointDataSource.cs 93.75% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7874      +/-   ##
==========================================
- Coverage   65.74%   61.23%   -4.51%     
==========================================
  Files        2219     2221       +2     
  Lines       98064    98116      +52     
  Branches     8849     8859      +10     
==========================================
- Hits        64471    60081    -4390     
- Misses      31379    35918    +4539     
+ Partials     2214     2117      -97     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

t:tech-debt Change Type - Tech debt

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant