Skip to content

Commit 3c9a761

Browse files
Allow IDocument to be modified before rendering (#344)
1 parent e7e2acf commit 3c9a761

File tree

22 files changed

+305
-3
lines changed

22 files changed

+305
-3
lines changed

docs/openapi.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,36 @@ http://localhost:7071/api/swagger/ui?tag=product,option
196196
http://localhost:7071/api/swagger.json?tag=product,option
197197
```
198198

199+
## Modifying Swagger and OpenAPI documents ##
200+
201+
If the generated document needs to be modified in more complex ways, you can use an `IDocumentFilter` that can modify the Swagger and
202+
OpenAPI documents just before it is rendered to the client. To register such a filter you must create a class that inherits from the
203+
`DefaultOpenApiConfigurationOptions` class and add your `IDocumentFilter` to its `DocumentFilters` list:
204+
205+
```csharp
206+
207+
public class OpenApiConfigurationOptions : DefaultOpenApiConfigurationOptions
208+
{
209+
public OpenApiConfigurationOptions()
210+
{
211+
this.DocumentFilters.Add(new ExampleDocumentFilter());
212+
}
213+
}
214+
215+
```
216+
217+
This code adds the `ExampleDocumentFilter` class to the list of document filters. Within a document filter you access to an `IHttpRequestDataObject`
218+
object, which contains request data like the current host and scheme, and to the `OpenApiDocument` object which contains all the generated documentation.
219+
220+
```csharp
221+
public class ExampleDocumentFilter : IDocumentFilter
222+
{
223+
public void Apply(IHttpRequestDataObject request, OpenApiDocument document)
224+
{
225+
226+
}
227+
}
228+
```
199229

200230
## Further Authentication and Authorisation ##
201231

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netstandard2.0</TargetFramework>
5+
</PropertyGroup>
6+
7+
<ItemGroup>
8+
<ProjectReference Include="..\..\src\Microsoft.Azure.WebJobs.Extensions.OpenApi.Core\Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.csproj" />
9+
</ItemGroup>
10+
11+
</Project>

samples/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.InProc/Microsoft.Azure.WebJobs.Extensions.OpenApi.FunctionApp.InProc.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<TargetFramework>net6.0</TargetFramework>

src/Microsoft.Azure.Functions.Worker.Extensions.OpenApi/Document.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Microsoft.Azure.Functions.Worker.Extensions.OpenApi.Extensions;
99
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions;
1010
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Enums;
11+
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Filters;
1112
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Visitors;
1213
using Microsoft.OpenApi;
1314
using Microsoft.OpenApi.Models;
@@ -201,6 +202,17 @@ public IDocument Build(Assembly assembly, OpenApiVersionType version = OpenApiVe
201202
return this;
202203
}
203204

205+
/// <inheritdoc />
206+
public IDocument ApplyDocumentFilters(DocumentFilterCollection collection)
207+
{
208+
foreach (var filter in GenericExtensions.ThrowIfNullOrDefault(collection).DocumentFilters)
209+
{
210+
filter.Apply(this._req, this.OpenApiDocument);
211+
}
212+
213+
return this;
214+
}
215+
204216
/// <inheritdoc />
205217
public async Task<string> RenderAsync(OpenApiSpecVersion version, OpenApiFormat format)
206218
{

src/Microsoft.Azure.Functions.Worker.Extensions.OpenApi/Functions/OpenApiTriggerFunction.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ public async Task<HttpResponseData> RenderSwaggerDocument(HttpRequestData req, s
6464
.AddNamingStrategy(this._context.NamingStrategy)
6565
.AddVisitors(this._context.GetVisitorCollection())
6666
.Build(this._context.ApplicationAssembly, this._context.OpenApiConfigurationOptions.OpenApiVersion)
67+
.ApplyDocumentFilters(this._context.GetDocumentFilterCollection())
6768
.RenderAsync(this._context.GetOpenApiSpecVersion(this._context.OpenApiConfigurationOptions.OpenApiVersion), this._context.GetOpenApiFormat(extension))
6869
.ConfigureAwait(false);
6970

@@ -123,6 +124,7 @@ public async Task<HttpResponseData> RenderOpenApiDocument(HttpRequestData req, s
123124
.AddNamingStrategy(this._context.NamingStrategy)
124125
.AddVisitors(this._context.GetVisitorCollection())
125126
.Build(this._context.ApplicationAssembly, this._context.GetOpenApiVersionType(version))
127+
.ApplyDocumentFilters(this._context.GetDocumentFilterCollection())
126128
.RenderAsync(this._context.GetOpenApiSpecVersion(version), this._context.GetOpenApiFormat(extension))
127129
.ConfigureAwait(false);
128130

src/Microsoft.Azure.Functions.Worker.Extensions.OpenApi/OpenApiHttpTriggerContext.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Configurations;
1212
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Enums;
1313
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Extensions;
14+
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Filters;
1415
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Resolvers;
1516
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Visitors;
1617
using Microsoft.OpenApi;
@@ -239,6 +240,14 @@ public virtual string GetSwaggerAuthKey(string key = "OpenApi__ApiKey")
239240
return value ?? string.Empty;
240241
}
241242

243+
/// <inheritdoc />
244+
public virtual DocumentFilterCollection GetDocumentFilterCollection()
245+
{
246+
var collection = new DocumentFilterCollection(this.OpenApiConfigurationOptions.DocumentFilters);
247+
248+
return collection;
249+
}
250+
242251
private string GetRuntimePath(string functionAppDirectory, bool appendBin)
243252
{
244253
var path = functionAppDirectory;

src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/Abstractions/IDocument.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Threading.Tasks;
33

44
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Enums;
5+
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Filters;
56
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Visitors;
67
using Microsoft.OpenApi;
78
using Microsoft.OpenApi.Models;
@@ -72,6 +73,13 @@ public interface IDocument
7273
/// <returns><see cref="IDocument"/> instance.</returns>
7374
IDocument Build(Assembly assembly, OpenApiVersionType version = OpenApiVersionType.V2);
7475

76+
/// <summary>
77+
/// Applies the given <see cref="DocumentFilterCollection"/> to the <see cref="IDocument"/>.
78+
/// </summary>
79+
/// <param name="collection"><see cref="DocumentFilterCollection"/> instance.</param>
80+
/// <returns></returns>
81+
IDocument ApplyDocumentFilters(DocumentFilterCollection collection);
82+
7583
/// <summary>
7684
/// Renders OpenAPI document.
7785
/// </summary>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using Microsoft.OpenApi.Models;
2+
3+
namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions
4+
{
5+
/// <summary>
6+
/// This interface allows creating custom document filters to modify the contents of the OpenApi / Swagger documentation before it is rendered.
7+
/// </summary>
8+
public interface IDocumentFilter
9+
{
10+
/// <summary>
11+
/// This method is invoked after the <see cref="IDocument"/> has been built and just before it is rendered and returned to the client.
12+
/// </summary>
13+
/// <param name="request">The HTTP request.</param>
14+
/// <param name="document">The generated document.</param>
15+
void Apply(IHttpRequestDataObject request, OpenApiDocument document);
16+
}
17+
}

src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/Abstractions/IOpenApiConfigurationOptions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,10 @@ public interface IOpenApiConfigurationOptions
3939
/// Gets or sets the value indicating whether to force the HTTPS protocol or not.
4040
/// </summary>
4141
bool ForceHttps { get; set; }
42+
43+
/// <summary>
44+
/// Gets or sets the list of <see cref="IDocumentFilter"/> instances.
45+
/// </summary>
46+
List<IDocumentFilter> DocumentFilters { get; set; }
4247
}
4348
}

src/Microsoft.Azure.WebJobs.Extensions.OpenApi.Core/Abstractions/IOpenApiHttpTriggerContext.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Configurations;
66
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Enums;
7+
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Filters;
78
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Visitors;
89
using Microsoft.OpenApi;
910

@@ -144,5 +145,11 @@ public interface IOpenApiHttpTriggerContext
144145
/// <param name="key">Environment variables key to look for.</param>
145146
/// <returns>Returns the API key for endpoints.</returns>
146147
string GetSwaggerAuthKey(string key = "OpenApi__ApiKey");
148+
149+
/// <summary>
150+
/// Returns the <see cref="DocumentFilterCollection"/> containing the configured <see cref="IDocumentFilter"/> instances.
151+
/// </summary>
152+
/// <returns>Returns the <see cref="DocumentFilterCollection"/> instance.</returns>
153+
DocumentFilterCollection GetDocumentFilterCollection();
147154
}
148155
}

0 commit comments

Comments
 (0)