Skip to content

Add API to support dyanmically generated OpenAPI schemas in document #60589

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
captainsafia opened this issue Feb 24, 2025 · 4 comments
Closed
Assignees
Labels
api-approved API was approved in API review, it can be implemented area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates feature-openapi
Milestone

Comments

@captainsafia
Copy link
Member

captainsafia commented Feb 24, 2025

Background and Motivation

The current OpenAPI implementation in ASP.NET Core lacks support for being able to dynamically generate OpenAPI schemas and insert them into the document. Without built-in APIs for this, evelopers must manually write the schemas for types in their application that need to be referenced automatically. While this can be straightforward for simple types, it grows complicated for DTOs and more complex types in the user application. Furthermore, developers can't take advantage of the built-in logic the OpenAPI implementation has to support resolving metadata from ParameterInfo and route constraints.

  • The GetOrCreateSchema API takes a type and an ApiParameterDescription to support being able to generate schemas for the type and apply any metadata from the ParameterInfo to it.
  • The Document property is added to the transformer contexts to allow users to interact with the components store, provided by the underlying Microsoft.OpenApi library.

Proposed API

namespace Microsoft.AspNetCore.OpenApi;

+public interface IOpenApiSchemaProvider
+{
+    Task<OpenApiSchema> GetOrCreateSchemaAsync(System.Type type, Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterDescription? parameterDescription = null, CancellationToken = default);
+}

public sealed class OpenApiDocumentTransformerContext  : IOpenApiSchemaProvider
{
+    public Task<OpenApiSchema> GetOrCreateSchemaAsync(System.Type type, Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterDescription? parameterDescription = null, CancellationToken = default);
}

public sealed class OpenApiOperationTransformerContext : IOpenApiSchemaProvider
{
+    public Microsoft.OpenApi.Models.OpenApiDocument Document { get; init; }
+    public Task<OpenApiSchema> GetOrCreateSchemaAsync(System.Type type, Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterDescription? parameterDescription = null, CancellationToken = default);
}

public sealed class OpenApiSchemaTransformerContext : IOpenApiSchemaProvider
{
+    public Microsoft.OpenApi.Models.OpenApiDocument Document { get; init; }
+    public Task<OpenApiSchema> GetOrCreateSchemaAsync(System.Type type, Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterDescription? parameterDescription = null, CancellationToken = default);
}

Usage Examples

builder.Services.AddOpenApi("v1", options =>
{
options.AddOperationTransformer(async (operation, context, cancellationToken) =>
  {      
      // Generate schema for error responses
      var errorSchema = await context.GetOrCreateSchemaAsync(typeof(ProblemDetails), cancellationToken);
      context.Document.AddComponent("Error", errorSchema);
      
      // Reference the schema in responses
      operation.Responses["500"] = new OpenApiResponse
      {
          Description = "Error",
          Content =
          {
              ["application/problem+json"] = new OpenApiMediaType
              {
                  Schema = new OpenApiSchemaReference("Error", context.Document)
              }
          }
      };
      
      return Task.CompletedTask;
  });
});

Alternative Designs

N/A

Design Notes

The IOpenApiSchemaProvider type is not applied on the OpenApiSchemaService registered in the DI container. We opted not to do this in favor of restricting schema generation to the transformer APIs. This avoids the Microsoft.AspNetCore.OpenApi package becoming a generic schema generation API and allows us to limit the functionality to codepaths that we have more control over (OpenAPI document transformers).

Schema transformers registered in an API are applied to schemas that are generated by the service. This can increase the risk for re-entrant or recursive schema transformers to generate too many schemas if developers do not add guards against these cases.

Risks

  1. The new APIs are additions with no breaking changes to existing functionality.
  2. Performance impact should be minimal as schema generation is typically done once during startup or on-demand.
  3. The implementation only exposes APIs for generating schemas, the schema store is modeled directly on the OpenAPI document which is handled by a third-party API.
@captainsafia captainsafia added api-ready-for-review API is ready for formal API review - https://github.com/dotnet/apireviews area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates feature-openapi labels Feb 24, 2025
@captainsafia captainsafia added this to the 10.0-preview3 milestone Feb 24, 2025
@captainsafia captainsafia self-assigned this Feb 24, 2025
Copy link
Contributor

Thank you for submitting this for API review. This will be reviewed by @dotnet/aspnet-api-review at the next meeting of the ASP.NET Core API Review group. Please ensure you take a look at the API review process documentation and ensure that:

  • The PR contains changes to the reference-assembly that describe the API change. Or, you have included a snippet of reference-assembly-style code that illustrates the API change.
  • The PR describes the impact to users, both positive (useful new APIs) and negative (breaking changes).
  • Someone is assigned to "champion" this change in the meeting, and they understand the impact and design of the change.

@captainsafia
Copy link
Member Author

Moving this to Preview 4. The proposal still hasn't gone through API review and likely won't before code complete next week.

@halter73
Copy link
Member

API Review Notes:

  • Is adding the Document property with init; breaking?
    • Not if we don't make it required and do make it nullable.
  • Does Microsoft.AspNetCore.OpenApi currently expose or take any other ApiExplorer types?
  • Absolutely. The contexts have a lot of them.
  • Why is IOpenApiSchemaProvider an interface?
    • We could implement it in a singleton service in the future.
    • It helps ensure the signatures are consistent between the three context types.
    • We think we can keep the signature's the same without the interface.
    • We can always add it later. We don't think it'd be breaking for the contexts to implement a new interface, but even if it is, we just wouldn't implement it on the context types.
  • @captainsafia Says these should be async and has just updated the issue\

API Approved!

namespace Microsoft.AspNetCore.OpenApi;

public sealed class OpenApiDocumentTransformerContext
{
+    public Task<OpenApiSchema> GetOrCreateSchemaAsync(Type type, ApiParameterDescription? parameterDescription = null, CancellationToken cancellationToken = default);
}

public sealed class OpenApiOperationTransformerContext
{
+    public OpenApiDocument? Document { get; init; }
+    public Task<OpenApiSchema> GetOrCreateSchemaAsync(Type type, ApiParameterDescription? parameterDescription = null, CancellationToken cancellationToken = default);
}

public sealed class OpenApiSchemaTransformerContext
{
+    public OpenApiDocument? Document { get; init; }
+    public Task<OpenApiSchema> GetOrCreateSchemaAsync(Type type, ApiParameterDescription? parameterDescription = null, CancellationToken cancellationToken = default);
}

@halter73 halter73 added api-approved API was approved in API review, it can be implemented and removed api-ready-for-review API is ready for formal API review - https://github.com/dotnet/apireviews labels Mar 20, 2025
@captainsafia
Copy link
Member Author

Closing as supported in preview4.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-approved API was approved in API review, it can be implemented area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates feature-openapi
Projects
None yet
Development

No branches or pull requests

2 participants