Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions docs/openapi.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,36 @@ http://localhost:7071/api/swagger/ui?tag=product,option
http://localhost:7071/api/swagger.json?tag=product,option
```

## Modifying Swagger and OpenAPI documents ##

If the generated document needs to be modified in more complex ways, you can use an `IDocumentFilter` that can modify the Swagger and
OpenAPI documents just before it is rendered to the client. To register such a filter you must create a class that inherits from the
`DefaultOpenApiConfigurationOptions` class and add your `IDocumentFilter` to its `DocumentFilters` list:

```csharp

public class OpenApiConfigurationOptions : DefaultOpenApiConfigurationOptions
{
public OpenApiConfigurationOptions()
{
this.DocumentFilters.Add(new ExampleDocumentFilter());
}
}

```

This code adds the `ExampleDocumentFilter` class to the list of document filters. Within a document filter you access to an `IHttpRequestDataObject`
object, which contains request data like the current host and scheme, and to the `OpenApiDocument` object which contains all the generated documentation.

```csharp
public class ExampleDocumentFilter : IDocumentFilter
{
public void Apply(IHttpRequestDataObject request, OpenApiDocument document)
{

}
}
```

## Further Authentication and Authorisation ##

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.Azure.WebJobs.Extensions.OpenApi.Core\Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Microsoft.Azure.Functions.Worker.Extensions.OpenApi.Extensions;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Enums;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Filters;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Visitors;
using Microsoft.OpenApi;
using Microsoft.OpenApi.Models;
Expand Down Expand Up @@ -201,6 +202,17 @@ public IDocument Build(Assembly assembly, OpenApiVersionType version = OpenApiVe
return this;
}

/// <inheritdoc />
public IDocument ApplyDocumentFilters(DocumentFilterCollection collection)
{
foreach (var filter in GenericExtensions.ThrowIfNullOrDefault(collection).DocumentFilters)
{
filter.Apply(this._req, this.OpenApiDocument);
}

return this;
}

/// <inheritdoc />
public async Task<string> RenderAsync(OpenApiSpecVersion version, OpenApiFormat format)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public async Task<HttpResponseData> RenderSwaggerDocument(HttpRequestData req, s
.AddNamingStrategy(this._context.NamingStrategy)
.AddVisitors(this._context.GetVisitorCollection())
.Build(this._context.ApplicationAssembly, this._context.OpenApiConfigurationOptions.OpenApiVersion)
.ApplyDocumentFilters(this._context.GetDocumentFilterCollection())
.RenderAsync(this._context.GetOpenApiSpecVersion(this._context.OpenApiConfigurationOptions.OpenApiVersion), this._context.GetOpenApiFormat(extension))
.ConfigureAwait(false);

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Configurations;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Enums;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Extensions;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Filters;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Resolvers;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Visitors;
using Microsoft.OpenApi;
Expand Down Expand Up @@ -239,6 +240,14 @@ public virtual string GetSwaggerAuthKey(string key = "OpenApi__ApiKey")
return value ?? string.Empty;
}

/// <inheritdoc />
public virtual DocumentFilterCollection GetDocumentFilterCollection()
{
var collection = new DocumentFilterCollection(this.OpenApiConfigurationOptions.DocumentFilters);

return collection;
}

private string GetRuntimePath(string functionAppDirectory, bool appendBin)
{
var path = functionAppDirectory;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Threading.Tasks;

using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Enums;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Filters;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Visitors;
using Microsoft.OpenApi;
using Microsoft.OpenApi.Models;
Expand Down Expand Up @@ -72,6 +73,13 @@ public interface IDocument
/// <returns><see cref="IDocument"/> instance.</returns>
IDocument Build(Assembly assembly, OpenApiVersionType version = OpenApiVersionType.V2);

/// <summary>
/// Applies the given <see cref="DocumentFilterCollection"/> to the <see cref="IDocument"/>.
/// </summary>
/// <param name="collection"><see cref="DocumentFilterCollection"/> instance.</param>
/// <returns></returns>
IDocument ApplyDocumentFilters(DocumentFilterCollection collection);

/// <summary>
/// Renders OpenAPI document.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Microsoft.OpenApi.Models;

namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions
{
/// <summary>
/// This interface allows creating custom document filters to modify the contents of the OpenApi / Swagger documentation before it is rendered.
/// </summary>
public interface IDocumentFilter
{
/// <summary>
/// This method is invoked after the <see cref="IDocument"/> has been built and just before it is rendered and returned to the client.
/// </summary>
/// <param name="request">The HTTP request.</param>
/// <param name="document">The generated document.</param>
void Apply(IHttpRequestDataObject request, OpenApiDocument document);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,10 @@ public interface IOpenApiConfigurationOptions
/// Gets or sets the value indicating whether to force the HTTPS protocol or not.
/// </summary>
bool ForceHttps { get; set; }

/// <summary>
/// Gets or sets the list of <see cref="IDocumentFilter"/> instances.
/// </summary>
List<IDocumentFilter> DocumentFilters { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Configurations;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Enums;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Filters;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Visitors;
using Microsoft.OpenApi;

Expand Down Expand Up @@ -144,5 +145,11 @@ public interface IOpenApiHttpTriggerContext
/// <param name="key">Environment variables key to look for.</param>
/// <returns>Returns the API key for endpoints.</returns>
string GetSwaggerAuthKey(string key = "OpenApi__ApiKey");

/// <summary>
/// Returns the <see cref="DocumentFilterCollection"/> containing the configured <see cref="IDocumentFilter"/> instances.
/// </summary>
/// <returns>Returns the <see cref="DocumentFilterCollection"/> instance.</returns>
DocumentFilterCollection GetDocumentFilterCollection();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ public class DefaultOpenApiConfigurationOptions : IOpenApiConfigurationOptions
/// <inheritdoc />
public bool ForceHttps { get; set; } = IsHttpsForced();

/// <inheritdoc />
public List<IDocumentFilter> DocumentFilters { get; set; } = new List<IDocumentFilter>();

/// <summary>
/// Gets the OpenAPI document version.
/// </summary>
Expand Down Expand Up @@ -118,7 +121,7 @@ protected static bool IsFunctionsRuntimeEnvironmentDevelopment()
/// <returns>Returns <c>True</c>, if HTTP is forced; otherwise returns <c>False</c>.</returns>
protected static bool IsHttpForced()
{
var development = bool.TryParse(Environment.GetEnvironmentVariable(ForceHttpKey), out var result) ? result : false;;
var development = bool.TryParse(Environment.GetEnvironmentVariable(ForceHttpKey), out var result) ? result : false;

return development;
}
Expand All @@ -129,7 +132,7 @@ protected static bool IsHttpForced()
/// <returns>Returns <c>True</c>, if HTTPS is forced; otherwise returns <c>False</c>.</returns>
protected static bool IsHttpsForced()
{
var development = bool.TryParse(Environment.GetEnvironmentVariable(ForceHttpsKey), out var result) ? result : false;;
var development = bool.TryParse(Environment.GetEnvironmentVariable(ForceHttpsKey), out var result) ? result : false;

return development;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,8 @@ public sealed class OpenApiSettings : IOpenApiConfigurationOptions

/// <inheritdoc />
public bool ForceHttps { get; set; }

/// <inheritdoc />
public List<IDocumentFilter> DocumentFilters { get; set; } = new List<IDocumentFilter>();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.Collections.Generic;

using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Extensions;

namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Filters
{
/// <summary>
/// This represents the collection entity for <see cref="IDocumentFilter"/> instances.
/// </summary>
public class DocumentFilterCollection
{
/// <summary>
/// Initializes a new instance of the <see cref="DocumentFilterCollection"/> class.
/// </summary>
/// <param name="documentFilters">List of <see cref="IDocumentFilter"/> instances.</param>
public DocumentFilterCollection(List<IDocumentFilter> documentFilters)
{
this.DocumentFilters = documentFilters.ThrowIfNullOrDefault();
}

/// <summary>
/// Gets the list of <see cref="IDocumentFilter"/> instances.
/// </summary>
public List<IDocumentFilter> DocumentFilters { get; set; }
}
}
12 changes: 12 additions & 0 deletions src/Microsoft.Azure.WebJobs.Extensions.OpenApi/Document.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Enums;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Extensions;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Filters;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Visitors;
using Microsoft.OpenApi;
using Microsoft.OpenApi.Models;
Expand Down Expand Up @@ -196,6 +197,17 @@ public IDocument Build(Assembly assembly, OpenApiVersionType version = OpenApiVe
return this;
}

/// <inheritdoc />
public IDocument ApplyDocumentFilters(DocumentFilterCollection collection)
{
foreach (var filter in collection.ThrowIfNullOrDefault().DocumentFilters)
{
filter.Apply(this._req, this.OpenApiDocument);
}

return this;
}

/// <inheritdoc />
public async Task<string> RenderAsync(OpenApiSpecVersion version, OpenApiFormat format)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Configurations;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Enums;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Extensions;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Filters;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Resolvers;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Visitors;
using Microsoft.OpenApi;
Expand Down Expand Up @@ -239,6 +240,14 @@ public virtual string GetSwaggerAuthKey(string key = "OpenApi__ApiKey")
return value ?? string.Empty;
}

/// <inheritdoc />
public virtual DocumentFilterCollection GetDocumentFilterCollection()
{
var collection = new DocumentFilterCollection(this.OpenApiConfigurationOptions.DocumentFilters);

return collection;
}

private string GetRuntimePath(string functionAppDirectory, bool appendBin)
{
var path = functionAppDirectory;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public static async Task<IActionResult> RenderSwaggerDocument(HttpRequest req, s
.AddNamingStrategy(context.NamingStrategy)
.AddVisitors(context.GetVisitorCollection())
.Build(context.ApplicationAssembly, context.OpenApiConfigurationOptions.OpenApiVersion)
.ApplyDocumentFilters(context.GetDocumentFilterCollection())
.RenderAsync(context.GetOpenApiSpecVersion(context.OpenApiConfigurationOptions.OpenApiVersion), context.GetOpenApiFormat(extension))
.ConfigureAwait(false);

Expand Down Expand Up @@ -135,6 +136,7 @@ public static async Task<IActionResult> RenderOpenApiDocument(HttpRequest req, s
.AddNamingStrategy(context.NamingStrategy)
.AddVisitors(context.GetVisitorCollection())
.Build(context.ApplicationAssembly, context.GetOpenApiVersionType(version))
.ApplyDocumentFilters(context.GetDocumentFilterCollection())
.RenderAsync(context.GetOpenApiSpecVersion(version), context.GetOpenApiFormat(extension))
.ConfigureAwait(false);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Net.Http;
using System.Threading.Tasks;

using FluentAssertions;

using Microsoft.VisualStudio.TestTools.UnitTesting;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.Document.Tests
{
[TestClass]
[TestCategory(Constants.TestCategory)]
public class Get_DocumentFilter_Tests
{
private static HttpClient http = new HttpClient();

private JObject _doc;

[TestInitialize]
public async Task Init()
{
var json = await http.GetStringAsync(Constants.OpenApiDocEndpoint).ConfigureAwait(false);
this._doc = JsonConvert.DeserializeObject<JObject>(json);
}

[TestMethod]
public void Given_Rewritten_OpenApiDocument_Then_It_Should_Have_Modified_Description()
{
var modifiedDescription = this._doc["paths"]["/get-documentfilter"]["get"]["responses"]["200"].Value<string>("description");

modifiedDescription.Should().Be("The OK response rewritten");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Configurations;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Enums;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.TestApp.DocumentFilters;
using Microsoft.OpenApi.Models;

namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.TestApp.Configurations
Expand All @@ -19,6 +20,11 @@ public class OpenApiConfigurationOptions : DefaultOpenApiConfigurationOptions
public const string LicenseUrl = "http://opensource.org/licenses/MIT";
public const OpenApiVersionType OpenApiSpecVersion = OpenApiVersionType.V3;

public OpenApiConfigurationOptions()
{
this.DocumentFilters.Add(new RewriteDescriptionDocumentFilter());
}

public override OpenApiInfo Info { get; set; } = new OpenApiInfo()
{
Version = DocVersion,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Abstractions;
using Microsoft.OpenApi.Models;

namespace Microsoft.Azure.WebJobs.Extensions.OpenApi.TestApp.DocumentFilters
{
internal class RewriteDescriptionDocumentFilter : IDocumentFilter
{
public void Apply(IHttpRequestDataObject request, OpenApiDocument document)
{
if (document.Paths.ContainsKey("/get-documentfilter"))
{
document
.Paths["/get-documentfilter"]
.Operations[OperationType.Get]
.Responses["200"]
.Description += " rewritten";
}
}
}
}
Loading