Skip to content

Commit

Permalink
Support returning OpenAPI document in YAML from MapOpenApi (#58616)
Browse files Browse the repository at this point in the history
* Support returning OpenAPI document in YAML from MapOpenApi

* Update tests and YAML content type
  • Loading branch information
captainsafia committed Feb 11, 2025
1 parent f19e167 commit b022857
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 11 deletions.
1 change: 1 addition & 0 deletions src/OpenApi/sample/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
var app = builder.Build();

app.MapOpenApi();
app.MapOpenApi("/openapi/{documentName}.yaml");
if (app.Environment.IsDevelopment())
{
app.MapSwaggerUi();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,16 @@ public static IEndpointConventionBuilder MapOpenApi(this IEndpointRouteBuilder e
using var writer = Utf8BufferTextWriter.Get(output);
try
{
document.Serialize(new OpenApiJsonWriter(writer), documentOptions.OpenApiVersion);
context.Response.ContentType = "application/json;charset=utf-8";
if (UseYaml(pattern))
{
document.Serialize(new OpenApiYamlWriter(writer), documentOptions.OpenApiVersion);
context.Response.ContentType = "text/plain+yaml;charset=utf-8";
}
else
{
document.Serialize(new OpenApiJsonWriter(writer), documentOptions.OpenApiVersion);
context.Response.ContentType = "application/json;charset=utf-8";
}
await context.Response.BodyWriter.WriteAsync(output.ToArray(), context.RequestAborted);
await context.Response.BodyWriter.FlushAsync(context.RequestAborted);
}
Expand All @@ -63,4 +71,8 @@ public static IEndpointConventionBuilder MapOpenApi(this IEndpointRouteBuilder e
}
}).ExcludeFromDescription();
}

private static bool UseYaml(string pattern) =>
pattern.EndsWith(".yaml", StringComparison.OrdinalIgnoreCase) ||
pattern.EndsWith(".yml", StringComparison.OrdinalIgnoreCase);
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@ public void MapOpenApi_ReturnsEndpointConventionBuilder()
Assert.IsAssignableFrom<IEndpointConventionBuilder>(returnedBuilder);
}

[Fact]
public void MapOpenApi_SupportsCustomizingPath()
[Theory]
[InlineData("/custom/{documentName}/openapi.json")]
[InlineData("/custom/{documentName}/openapi.yaml")]
[InlineData("/custom/{documentName}/openapi.yml")]
public void MapOpenApi_SupportsCustomizingPath(string expectedPath)
{
// Arrange
var expectedPath = "/custom/{documentName}/openapi.json";
var serviceProvider = CreateServiceProvider();
var builder = new DefaultEndpointRouteBuilder(new ApplicationBuilder(serviceProvider));

Expand Down Expand Up @@ -72,13 +74,17 @@ public async Task MapOpenApi_ReturnsRenderedDocument()
});
}

[Fact]
public async Task MapOpenApi_ReturnsDefaultDocumentIfNoNameProvided()
[Theory]
[InlineData("/openapi.json", "application/json;charset=utf-8", false)]
[InlineData("/openapi.toml", "application/json;charset=utf-8", false)]
[InlineData("/openapi.yaml", "text/plain+yaml;charset=utf-8", true)]
[InlineData("/openapi.yml", "text/plain+yaml;charset=utf-8", true)]
public async Task MapOpenApi_ReturnsDefaultDocumentIfNoNameProvided(string expectedPath, string expectedContentType, bool isYaml)
{
// Arrange
var serviceProvider = CreateServiceProvider();
var builder = new DefaultEndpointRouteBuilder(new ApplicationBuilder(serviceProvider));
builder.MapOpenApi("/openapi.json");
builder.MapOpenApi(expectedPath);
var context = new DefaultHttpContext();
var responseBodyStream = new MemoryStream();
context.Response.Body = responseBodyStream;
Expand All @@ -91,6 +97,11 @@ public async Task MapOpenApi_ReturnsDefaultDocumentIfNoNameProvided()

// Assert
Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode);
Assert.Equal(expectedContentType, context.Response.ContentType);
var responseString = Encoding.UTF8.GetString(responseBodyStream.ToArray());
// String check to validate that generated document starts with YAML syntax
Assert.Equal(isYaml, responseString.StartsWith("openapi: 3.0.1", StringComparison.OrdinalIgnoreCase));
responseBodyStream.Position = 0;
ValidateOpenApiDocument(responseBodyStream, document =>
{
Assert.Equal("OpenApiEndpointRouteBuilderExtensionsTests | v1", document.Info.Title);
Expand Down Expand Up @@ -121,16 +132,19 @@ public async Task MapOpenApi_Returns404ForUnresolvedDocument()
Assert.Equal("No OpenAPI document with the name 'v2' was found.", Encoding.UTF8.GetString(responseBodyStream.ToArray()));
}

[Fact]
public async Task MapOpenApi_ReturnsDocumentIfNameProvidedInQuery()
[Theory]
[InlineData("/openapi.json", "application/json;charset=utf-8", false)]
[InlineData("/openapi.yaml", "text/plain+yaml;charset=utf-8", true)]
[InlineData("/openapi.yml", "text/plain+yaml;charset=utf-8", true)]
public async Task MapOpenApi_ReturnsDocumentIfNameProvidedInQuery(string expectedPath, string expectedContentType, bool isYaml)
{
// Arrange
var documentName = "v2";
var hostEnvironment = new HostEnvironment() { ApplicationName = nameof(OpenApiEndpointRouteBuilderExtensionsTests) };
var serviceProviderIsService = new ServiceProviderIsService();
var serviceProvider = CreateServiceProvider(documentName);
var builder = new DefaultEndpointRouteBuilder(new ApplicationBuilder(serviceProvider));
builder.MapOpenApi("/openapi.json");
builder.MapOpenApi(expectedPath);
var context = new DefaultHttpContext();
var responseBodyStream = new MemoryStream();
context.Response.Body = responseBodyStream;
Expand All @@ -144,6 +158,11 @@ public async Task MapOpenApi_ReturnsDocumentIfNameProvidedInQuery()

// Assert
Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode);
Assert.Equal(expectedContentType, context.Response.ContentType);
var responseString = Encoding.UTF8.GetString(responseBodyStream.ToArray());
// String check to validate that generated document starts with YAML syntax
Assert.Equal(isYaml, responseString.StartsWith("openapi: 3.0.1", StringComparison.OrdinalIgnoreCase));
responseBodyStream.Position = 0;
ValidateOpenApiDocument(responseBodyStream, document =>
{
Assert.Equal($"OpenApiEndpointRouteBuilderExtensionsTests | {documentName}", document.Info.Title);
Expand Down

0 comments on commit b022857

Please sign in to comment.