Skip to content

Commit 09a88c0

Browse files
authored
Prep Only: Customize OpenAPI: Update v10p4 OpenAPISchemas (#35471)
* Prep Only: Customize OpenAPI: Update v10 Prev 4 OpenAPISchemas in transformers
1 parent df02d7a commit 09a88c0

12 files changed

+863
-7
lines changed

aspnetcore/fundamentals/openapi/customize-openapi.md

+13-7
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ uid: fundamentals/openapi/customize-openapi
1010
---
1111
# Customize OpenAPI documents
1212

13+
:::moniker range=">= aspnetcore-10.0"
14+
1315
<a name="transformers"></a>
1416

1517
## OpenAPI document transformers
@@ -38,7 +40,7 @@ Transformers can be registered onto the document by calling the <xref:Microsoft.
3840
* Register a schema transformer using an instance of <xref:Microsoft.AspNetCore.OpenApi.IOpenApiSchemaTransformer>.
3941
* Register a schema transformer using a DI-activated <xref:Microsoft.AspNetCore.OpenApi.IOpenApiSchemaTransformer>.
4042

41-
[!code-csharp[](~/fundamentals/openapi/samples/9.x/WebMinOpenApi/Program.cs?name=snippet_transUse&highlight=8-19)]
43+
[!code-csharp[](~/fundamentals/openapi/samples/10.x/WebMinOpenApi/Program.cs?name=snippet_transUse&highlight=8-19)]
4244

4345
### Execution order for transformers
4446

@@ -58,7 +60,7 @@ For example, in the following snippet:
5860
* Both `DocumentTransformer1` and `DocumentTransformer2` are executed after all operations and schemas have been added to the document, so they have access to all modifications made by the operation and schema transformers.
5961
* `DocumentTransformer2` is executed after `DocumentTransformer1`, so it has access to the modifications made by `DocumentTransformer1`.
6062

61-
[!code-csharp[](~/fundamentals/openapi/samples/9.x/WebMinOpenApi/Program.cs?name=snippet_transInOut&highlight=6-14)]
63+
[!code-csharp[](~/fundamentals/openapi/samples/10.x/WebMinOpenApi/Program.cs?name=snippet_transInOut&highlight=6-14)]
6264

6365
## Use document transformers
6466

@@ -70,18 +72,18 @@ Document transformers have access to a context object that includes:
7072

7173
Document transformers can also mutate the OpenAPI document that is generated. The following example demonstrates a document transformer that adds some information about the API to the OpenAPI document.
7274

73-
[!code-csharp[](~/fundamentals/openapi/samples/9.x/WebMinOpenApi/Program.cs?name=snippet_documenttransformer1)]
75+
[!code-csharp[](~/fundamentals/openapi/samples/10.x/WebMinOpenApi/Program.cs?name=snippet_documenttransformer1)]
7476

7577
Service-activated document transformers can utilize instances from DI to modify the app. The following sample demonstrates a document transformer that uses the <xref:Microsoft.AspNetCore.Authentication.IAuthenticationSchemeProvider> service from the authentication layer. It checks if any JWT bearer-related schemes are registered in the app and adds them to the OpenAPI document's top level:
7678

77-
[!code-csharp[](~/fundamentals/openapi/samples/9.x/WebMinOpenApi/Program.cs?name=snippet_documenttransformer2)]
79+
[!code-csharp[](~/fundamentals/openapi/samples/10.x/WebMinOpenApi/Program.cs?name=snippet_documenttransformer2)]
7880

7981
Document transformers are unique to the document instance they're associated with. In the following example, a transformer:
8082

8183
* Registers authentication-related requirements to the `internal` document.
8284
* Leaves the `public` document unmodified.
8385

84-
[!code-csharp[](~/fundamentals/openapi/samples/9.x/WebMinOpenApi/Program.cs?name=snippet_multidoc_operationtransformer1)]
86+
[!code-csharp[](~/fundamentals/openapi/samples/10.x/WebMinOpenApi/Program.cs?name=snippet_multidoc_operationtransformer1)]
8587

8688
## Use operation transformers
8789

@@ -98,7 +100,7 @@ Operation transformers have access to a context object which contains:
98100

99101
For example, the following operation transformer adds `500` as a response status code supported by all operations in the document.
100102

101-
[!code-csharp[](~/fundamentals/openapi/samples/9.x/WebMinOpenApi/Program.cs?name=snippet_operationtransformer1)]
103+
[!code-csharp[](~/fundamentals/openapi/samples/10.x/WebMinOpenApi/Program.cs?name=snippet_operationtransformer1)]
102104

103105
## Use schema transformers
104106

@@ -115,7 +117,7 @@ Schema transformers have access to a context object which contains:
115117

116118
For example, the following schema transformer sets the `format` of decimal types to `decimal` instead of `double`:
117119

118-
[!code-csharp[](~/fundamentals/openapi/samples/9.x/WebMinOpenApi/Program.cs?name=snippet_schematransformer1)]
120+
[!code-csharp[](~/fundamentals/openapi/samples/10.x/WebMinOpenApi/Program.cs?name=snippet_schematransformer1)]
119121

120122
## Customize schema reuse
121123

@@ -158,3 +160,7 @@ builder.Services.AddOpenApi(options =>
158160

159161
* <xref:fundamentals/openapi/using-openapi-documents>
160162
* [OpenAPI specification](https://spec.openapis.org/oas/v3.0.3)
163+
164+
:::moniker-end
165+
166+
[!INCLUDE[](~/fundamentals/openapi/includes/customize-openapi9.md)]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
:::moniker range="= aspnetcore-9.0"
2+
3+
<a name="transformers"></a>
4+
5+
## OpenAPI document transformers
6+
7+
Transformers provide an API for modifying the OpenAPI document with user-defined customizations. Transformers are useful for scenarios like:
8+
9+
* Adding parameters to all operations in a document.
10+
* Modifying descriptions for parameters or operations.
11+
* Adding top-level information to the OpenAPI document.
12+
13+
Transformers fall into three categories:
14+
15+
* Document transformers have access to the entire OpenAPI document. These can be used to make global modifications to the document.
16+
* Operation transformers apply to each individual operation. Each individual operation is a combination of path and HTTP method. These can be used to modify parameters or responses on endpoints.
17+
* Schema transformers apply to each schema in the document. These can be used to modify the schema of request or response bodies, or any nested schemas.
18+
19+
Transformers can be registered onto the document by calling the <xref:Microsoft.AspNetCore.OpenApi.OpenApiOptions.AddDocumentTransformer%2A> method on the <xref:Microsoft.AspNetCore.OpenApi.OpenApiOptions> object. The following snippet shows different ways to register transformers onto the document:
20+
21+
* Register a document transformer using a delegate.
22+
* Register a document transformer using an instance of <xref:Microsoft.AspNetCore.OpenApi.IOpenApiDocumentTransformer>.
23+
* Register a document transformer using a DI-activated <xref:Microsoft.AspNetCore.OpenApi.IOpenApiDocumentTransformer>.
24+
* Register an operation transformer using a delegate.
25+
* Register an operation transformer using an instance of <xref:Microsoft.AspNetCore.OpenApi.IOpenApiOperationTransformer>.
26+
* Register an operation transformer using a DI-activated <xref:Microsoft.AspNetCore.OpenApi.IOpenApiOperationTransformer>.
27+
* Register a schema transformer using a delegate.
28+
* Register a schema transformer using an instance of <xref:Microsoft.AspNetCore.OpenApi.IOpenApiSchemaTransformer>.
29+
* Register a schema transformer using a DI-activated <xref:Microsoft.AspNetCore.OpenApi.IOpenApiSchemaTransformer>.
30+
31+
[!code-csharp[](~/fundamentals/openapi/samples/9.x/WebMinOpenApi/Program.cs?name=snippet_transUse&highlight=8-19)]
32+
33+
### Execution order for transformers
34+
35+
Transformers are executed as follows:
36+
37+
* Schema transformers are executed when a schema is registered to the document. Schema transformers are executed in the order in which they were added.
38+
All schemas are added to the document before any operation processing occurs, so all schema transformers are executed before any operation transformers.
39+
* Operation transformers are executed when an operation is added to the document. Operation transformers are executed in the order in which they were added.
40+
All operations are added to the document before any document transformers are executed.
41+
* Document transformers are executed when the document is generated. This is the final pass over the document, and all operations and schemas have been add by this point.
42+
* When an app is configured to generate multiple OpenAPI documents, transformers are executed for each document independently.
43+
44+
For example, in the following snippet:
45+
* `SchemaTransformer2` is executed and has access to the modifications made by `SchemaTransformer1`.
46+
* Both `OperationTransformer1` and `OperationTransformer2` have access to the modifications made by both schema transformers for the types involved in the operation they are called to process.
47+
* `OperationTransformer2` is executed after `OperationTransformer1`, so it has access to the modifications made by `OperationTransformer1`.
48+
* Both `DocumentTransformer1` and `DocumentTransformer2` are executed after all operations and schemas have been added to the document, so they have access to all modifications made by the operation and schema transformers.
49+
* `DocumentTransformer2` is executed after `DocumentTransformer1`, so it has access to the modifications made by `DocumentTransformer1`.
50+
51+
[!code-csharp[](~/fundamentals/openapi/samples/9.x/WebMinOpenApi/Program.cs?name=snippet_transInOut&highlight=6-14)]
52+
53+
## Use document transformers
54+
55+
Document transformers have access to a context object that includes:
56+
57+
* The name of the document being modified.
58+
* The <xref:Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescriptionGroupCollectionProvider.ApiDescriptionGroups> associated with that document.
59+
* The <xref:System.IServiceProvider> used in document generation.
60+
61+
Document transformers can also mutate the OpenAPI document that is generated. The following example demonstrates a document transformer that adds some information about the API to the OpenAPI document.
62+
63+
[!code-csharp[](~/fundamentals/openapi/samples/9.x/WebMinOpenApi/Program.cs?name=snippet_documenttransformer1)]
64+
65+
Service-activated document transformers can utilize instances from DI to modify the app. The following sample demonstrates a document transformer that uses the <xref:Microsoft.AspNetCore.Authentication.IAuthenticationSchemeProvider> service from the authentication layer. It checks if any JWT bearer-related schemes are registered in the app and adds them to the OpenAPI document's top level:
66+
67+
[!code-csharp[](~/fundamentals/openapi/samples/9.x/WebMinOpenApi/Program.cs?name=snippet_documenttransformer2)]
68+
69+
Document transformers are unique to the document instance they're associated with. In the following example, a transformer:
70+
71+
* Registers authentication-related requirements to the `internal` document.
72+
* Leaves the `public` document unmodified.
73+
74+
[!code-csharp[](~/fundamentals/openapi/samples/9.x/WebMinOpenApi/Program.cs?name=snippet_multidoc_operationtransformer1)]
75+
76+
## Use operation transformers
77+
78+
Operations are unique combinations of HTTP paths and methods in an OpenAPI document. Operation transformers are helpful when a modification:
79+
80+
* Should be made to each endpoint in an app, or
81+
* Conditionally applied to certain routes.
82+
83+
Operation transformers have access to a context object which contains:
84+
85+
* The name of the document the operation belongs to.
86+
* The <xref:Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescription> associated with the operation.
87+
* The <xref:System.IServiceProvider> used in document generation.
88+
89+
For example, the following operation transformer adds `500` as a response status code supported by all operations in the document.
90+
91+
[!code-csharp[](~/fundamentals/openapi/samples/9.x/WebMinOpenApi/Program.cs?name=snippet_operationtransformer1)]
92+
93+
## Use schema transformers
94+
95+
Schemas are the data models that are used in request and response bodies in an OpenAPI document. Schema transformers are useful when a modification:
96+
97+
* Should be made to each schema in the document, or
98+
* Conditionally applied to certain schemas.
99+
100+
Schema transformers have access to a context object which contains:
101+
102+
* The name of the document the schema belongs to.
103+
* The JSON type information associated with the target schema.
104+
* The <xref:System.IServiceProvider> used in document generation.
105+
106+
For example, the following schema transformer sets the `format` of decimal types to `decimal` instead of `double`:
107+
108+
[!code-csharp[](~/fundamentals/openapi/samples/9.x/WebMinOpenApi/Program.cs?name=snippet_schematransformer1)]
109+
110+
## Customize schema reuse
111+
112+
After all transformers have been applied, the framework makes a pass over the document to transfer certain schemas
113+
to the `components.schemas` section, replacing them with `$ref` references to the transferred schema.
114+
This reduces the size of the document and makes it easier to read.
115+
116+
The details of this processing are complicated and might change in future versions of .NET, but in general:
117+
118+
* Schemas for class/record/struct types are replaced with a `$ref` to a schema in `components.schemas`
119+
if they appear more than once in the document.
120+
* Schemas for primitive types and standard collections are left inline.
121+
* Schemas for enum types are always replaced with a `$ref` to a schema in components.schemas.
122+
123+
Typically the name of the schema in `components.schemas` is the name of the class/record/struct type,
124+
but in some circumstances a different name must be used.
125+
126+
ASP.NET Core lets you customize which schemas are replaced with a `$ref` to a schema in `components.schemas`
127+
using the <xref:Microsoft.AspNetCore.OpenApi.OpenApiOptions.CreateSchemaReferenceId> property of <xref:Microsoft.AspNetCore.OpenApi.OpenApiOptions>.
128+
This property is a delegate that takes a <xref:System.Text.Json.Serialization.Metadata.JsonTypeInfo> object and returns the name of the schema
129+
in `components.schemas` that should be used for that type.
130+
The framework provides a default implementation of this delegate, <xref:Microsoft.AspNetCore.OpenApi.OpenApiOptions.CreateDefaultSchemaReferenceId%2A>
131+
that uses the name of the type, but you can replace it with your own implementation.
132+
133+
As a simple example of this customization, you might choose to always inline enum schemas.
134+
This is done by setting <xref:Microsoft.AspNetCore.OpenApi.OpenApiOptions.CreateSchemaReferenceId> to a delegate
135+
that returns null for enum types, and otherwise returns the value from the default implementation.
136+
The following code shows how to do this:
137+
138+
```csharp
139+
builder.Services.AddOpenApi(options =>
140+
{
141+
// Always inline enum schemas
142+
options.CreateSchemaReferenceId = (type) =>
143+
type.Type.IsEnum ? null : OpenApiOptions.CreateDefaultSchemaReferenceId(type);
144+
});
145+
```
146+
147+
## Additional resources
148+
149+
* <xref:fundamentals/openapi/using-openapi-documents>
150+
* [OpenAPI specification](https://spec.openapis.org/oas/v3.0.3)
151+
152+
:::moniker-end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
extends: ["spectral:oas"]

0 commit comments

Comments
 (0)