-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Merge feature/openapi to main #55182
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
Merged
Merged
Changes from 1 commit
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
05bf9dc
Add OpenAPI feature branch to Helix pipeline
captainsafia b6e09bd
Remove unneeded pipeline config
captainsafia cd344fa
Add entry-point APIs for OpenAPI support (#54789)
captainsafia 1c6cfeb
Support resolving OpenApiPaths entries from document (#54847)
captainsafia 72f4723
Support generating OpenAPI operation and associated fields (#54903)
captainsafia b341f8c
Add APIs for OpenAPI document transformers (#54935)
captainsafia e0c652d
Add support for generating OpenAPI parameters (#55041)
captainsafia 4fe1a1f
Add support for generating OpenAPI responses (#55020)
captainsafia d82dab5
Add support for generating OpenAPI request bodies (#55040)
captainsafia 4e5d668
Merge branch 'main' into feature/openapi
captainsafia 0cfce91
Address feedback
captainsafia ca61e34
Fix solution files after rename
captainsafia File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Add entry-point APIs for OpenAPI support (#54789)
* Add entry-point APIs for OpenAPI support * Apply suggestions from code review Co-authored-by: Martin Costello <[email protected]> Co-authored-by: Rick Anderson <[email protected]> * Update docs and pass cancellation token to WriteAsync * Address feedback * Remove trailing comma in slnf * Address more feedback * Seal OpenApiOptions --------- Co-authored-by: Martin Costello <[email protected]> Co-authored-by: Rick Anderson <[email protected]>
- Loading branch information
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
internal static class OpenApiEndpointRouteBuilderExtensions | ||
{ | ||
/// <summary> | ||
/// Helper method to render Swagger UI view for testing. | ||
/// </summary> | ||
public static IEndpointConventionBuilder MapSwaggerUi(this IEndpointRouteBuilder endpoints) | ||
{ | ||
return endpoints.MapGet("/swagger/{documentName}", (string documentName) => Results.Content($$""" | ||
<html> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<title>OpenAPI -- {{documentName}}</title> | ||
<link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist/swagger-ui.css"> | ||
</head> | ||
<body> | ||
<div id="swagger-ui"></div> | ||
|
||
<script src="https://unpkg.com/swagger-ui-dist/swagger-ui-standalone-preset.js"></script> | ||
<script src="https://unpkg.com/swagger-ui-dist/swagger-ui-bundle.js"></script> | ||
|
||
<script> | ||
window.onload = function() { | ||
const ui = SwaggerUIBundle({ | ||
url: "/openapi/{{documentName}}.json", | ||
dom_id: '#swagger-ui', | ||
deepLinking: true, | ||
presets: [ | ||
SwaggerUIBundle.presets.apis, | ||
SwaggerUIStandalonePreset | ||
], | ||
plugins: [ | ||
SwaggerUIBundle.plugins.DownloadUrl | ||
], | ||
layout: "StandaloneLayout", | ||
}) | ||
window.ui = ui | ||
} | ||
</script> | ||
</body> | ||
</html> | ||
""", "text/html")).ExcludeFromDescription(); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using Microsoft.AspNetCore.Builder; | ||
using Microsoft.AspNetCore.Mvc; | ||
|
||
var builder = WebApplication.CreateBuilder(args); | ||
|
||
builder.Services.AddOpenApi("v1"); | ||
builder.Services.AddOpenApi("v2"); | ||
|
||
var app = builder.Build(); | ||
|
||
app.MapOpenApi(); | ||
if (app.Environment.IsDevelopment()) | ||
{ | ||
app.MapSwaggerUi(); | ||
} | ||
|
||
var v1 = app.MapGroup("v1") | ||
.WithMetadata(new ApiExplorerSettingsAttribute { GroupName = "v1" }); | ||
|
||
var v2 = app.MapGroup("v2") | ||
.WithMetadata(new ApiExplorerSettingsAttribute { GroupName = "v2" }); | ||
|
||
v1.MapPost("/todos", (Todo todo) => Results.Created($"/todos/{todo.Id}", todo)); | ||
v1.MapGet("/todos/{id}", (int id) => new TodoWithDueDate(1, "Test todo", false, DateTime.Now.AddDays(1), DateTime.Now)); | ||
|
||
app.Run(); | ||
|
||
public record Todo(int Id, string Title, bool Completed, DateTime CreatedAt); | ||
public record TodoWithDueDate(int Id, string Title, bool Completed, DateTime CreatedAt, DateTime DueDate) : Todo(Id, Title, Completed, CreatedAt); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
{ | ||
"$schema": "https://json.schemastore.org/launchsettings.json", | ||
"iisSettings": { | ||
"windowsAuthentication": false, | ||
"anonymousAuthentication": true, | ||
"iisExpress": { | ||
"applicationUrl": "http://localhost:43164", | ||
"sslPort": 44391 | ||
} | ||
}, | ||
"profiles": { | ||
"http": { | ||
"commandName": "Project", | ||
"dotnetRunMessages": true, | ||
"launchBrowser": true, | ||
"applicationUrl": "http://localhost:5051", | ||
"environmentVariables": { | ||
"ASPNETCORE_ENVIRONMENT": "Development" | ||
} | ||
}, | ||
"https": { | ||
"commandName": "Project", | ||
"dotnetRunMessages": true, | ||
"launchBrowser": true, | ||
"applicationUrl": "https://localhost:7174;http://localhost:5051", | ||
"environmentVariables": { | ||
"ASPNETCORE_ENVIRONMENT": "Development" | ||
} | ||
}, | ||
"IIS Express": { | ||
"commandName": "IISExpress", | ||
"launchBrowser": true, | ||
"environmentVariables": { | ||
"ASPNETCORE_ENVIRONMENT": "Development" | ||
} | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<Project Sdk="Microsoft.NET.Sdk.Web"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework> | ||
<Nullable>enable</Nullable> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<Reference Include="Microsoft.AspNetCore" /> | ||
<Reference Include="Microsoft.AspNetCore.Hosting" /> | ||
<Reference Include="Microsoft.AspNetCore.OpenApi" /> | ||
<Reference Include="Microsoft.AspNetCore.Http" /> | ||
<Reference Include="Microsoft.AspNetCore.Http.Results" /> | ||
<Reference Include="Microsoft.AspNetCore.StaticFiles" /> | ||
<Reference Include="Microsoft.Extensions.FileProviders.Embedded" /> | ||
<Reference Include="Microsoft.AspNetCore.Mvc" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"Logging": { | ||
"LogLevel": { | ||
"Default": "Information", | ||
"Microsoft.AspNetCore": "Warning" | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"Logging": { | ||
"LogLevel": { | ||
"Default": "Information", | ||
"Microsoft.AspNetCore": "Warning" | ||
} | ||
}, | ||
"AllowedHosts": "*" | ||
} |
File renamed without changes.
65 changes: 65 additions & 0 deletions
65
src/OpenApi/src/Extensions/OpenApiEndpointRouteBuilderExtensions.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System.Diagnostics.CodeAnalysis; | ||
using Microsoft.AspNetCore.Http; | ||
using Microsoft.AspNetCore.Internal; | ||
using Microsoft.AspNetCore.OpenApi; | ||
using Microsoft.AspNetCore.Routing; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Options; | ||
using Microsoft.OpenApi.Extensions; | ||
using Microsoft.OpenApi.Writers; | ||
|
||
namespace Microsoft.AspNetCore.Builder; | ||
|
||
/// <summary> | ||
/// OpenAPI-related methods for <see cref="IEndpointRouteBuilder"/>. | ||
/// </summary> | ||
public static class OpenApiEndpointRouteBuilderExtensions | ||
{ | ||
/// <summary> | ||
/// Register an endpoint onto the current application for resolving the OpenAPI document associated | ||
/// with the current application. | ||
/// </summary> | ||
/// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/>.</param> | ||
/// <param name="pattern">The route to register the endpoint on. Must include the 'documentName' route parameter.</param> | ||
/// <returns>An <see cref="IEndpointRouteBuilder"/> that can be used to further customize the endpoint.</returns> | ||
public static IEndpointConventionBuilder MapOpenApi(this IEndpointRouteBuilder endpoints, [StringSyntax("Route")] string pattern = OpenApiConstants.DefaultOpenApiRoute) | ||
{ | ||
var options = endpoints.ServiceProvider.GetRequiredService<IOptionsMonitor<OpenApiOptions>>(); | ||
return endpoints.MapGet(pattern, async (HttpContext context, string documentName = OpenApiConstants.DefaultDocumentName) => | ||
{ | ||
// It would be ideal to use the `HttpResponseStreamWriter` to | ||
// asynchronously write to the response stream here but Microsoft.OpenApi | ||
// does not yet support async APIs on their writers. | ||
// See https://github.com/microsoft/OpenAPI.NET/issues/421 for more info. | ||
var documentService = context.RequestServices.GetKeyedService<OpenApiDocumentService>(documentName); | ||
if (documentService is null) | ||
{ | ||
context.Response.StatusCode = StatusCodes.Status404NotFound; | ||
context.Response.ContentType = "text/plain;charset=utf-8"; | ||
await context.Response.WriteAsync($"No OpenAPI document with the name '{documentName}' was found."); | ||
} | ||
else | ||
{ | ||
var document = await documentService.GetOpenApiDocumentAsync(); | ||
var documentOptions = options.Get(documentName); | ||
using var output = MemoryBufferWriter.Get(); | ||
using var writer = Utf8BufferTextWriter.Get(output); | ||
try | ||
{ | ||
document.Serialize(new OpenApiJsonWriter(writer), documentOptions.OpenApiVersion); | ||
await context.Response.BodyWriter.WriteAsync(output.ToArray()); | ||
await context.Response.BodyWriter.FlushAsync(); | ||
} | ||
finally | ||
{ | ||
MemoryBufferWriter.Return(output); | ||
Utf8BufferTextWriter.Return(writer); | ||
} | ||
|
||
} | ||
}).ExcludeFromDescription(); | ||
} | ||
} |
72 changes: 72 additions & 0 deletions
72
src/OpenApi/src/Extensions/OpenApiServiceCollectionExtensions.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using Microsoft.AspNetCore.OpenApi; | ||
using Microsoft.Extensions.ApiDescriptions; | ||
|
||
namespace Microsoft.Extensions.DependencyInjection; | ||
|
||
/// <summary> | ||
/// OpenAPI-related methods for <see cref="IServiceCollection"/>. | ||
/// </summary> | ||
public static class OpenApiServiceCollectionExtensions | ||
{ | ||
/// <summary> | ||
/// Adds OpenAPI services related to the given document name to the specified <see cref="IServiceCollection"/>. | ||
/// </summary> | ||
/// <param name="services">The <see cref="IServiceCollection"/> to register services onto.</param> | ||
/// <param name="documentName">The name of the OpenAPI document associated with registered services.</param> | ||
public static IServiceCollection AddOpenApi(this IServiceCollection services, string documentName) | ||
{ | ||
ArgumentNullException.ThrowIfNull(services); | ||
|
||
return services.AddOpenApi(documentName, _ => { }); | ||
} | ||
|
||
/// <summary> | ||
/// Adds OpenAPI services related to the given document name to the specified <see cref="IServiceCollection"/> with the specified options. | ||
/// </summary> | ||
/// <param name="services">The <see cref="IServiceCollection"/> to register services onto.</param> | ||
/// <param name="documentName">The name of the OpenAPI document associated with registered services.</param> | ||
/// <param name="configureOptions">A delegate used to configure the target <see cref="OpenApiOptions"/>.</param> | ||
public static IServiceCollection AddOpenApi(this IServiceCollection services, string documentName, Action<OpenApiOptions> configureOptions) | ||
{ | ||
ArgumentNullException.ThrowIfNull(services); | ||
ArgumentNullException.ThrowIfNull(configureOptions); | ||
|
||
services.AddOpenApiCore(documentName); | ||
services.Configure<OpenApiOptions>(documentName, options => | ||
{ | ||
options.DocumentName = documentName; | ||
configureOptions(options); | ||
}); | ||
return services; | ||
} | ||
|
||
/// <summary> | ||
/// Adds OpenAPI services related to the default document to the specified <see cref="IServiceCollection"/> with the specified options. | ||
/// </summary> | ||
/// <param name="services">The <see cref="IServiceCollection"/> to register services onto.</param> | ||
/// <param name="configureOptions">A delegate used to configure the target <see cref="OpenApiOptions"/>.</param> | ||
public static IServiceCollection AddOpenApi(this IServiceCollection services, Action<OpenApiOptions> configureOptions) | ||
=> services.AddOpenApi(OpenApiConstants.DefaultDocumentName, configureOptions); | ||
|
||
/// <summary> | ||
/// Adds OpenAPI services related to the default document to the specified <see cref="IServiceCollection"/>. | ||
/// </summary> | ||
/// <param name="services">The <see cref="IServiceCollection"/> to register services onto.</param> | ||
public static IServiceCollection AddOpenApi(this IServiceCollection services) | ||
=> services.AddOpenApi(OpenApiConstants.DefaultDocumentName); | ||
|
||
private static IServiceCollection AddOpenApiCore(this IServiceCollection services, string documentName) | ||
{ | ||
services.AddEndpointsApiExplorer(); | ||
services.AddKeyedSingleton<OpenApiComponentService>(documentName); | ||
services.AddKeyedSingleton<OpenApiDocumentService>(documentName); | ||
// Required for build-time generation | ||
services.AddSingleton<IDocumentProvider, OpenApiDocumentProvider>(); | ||
// Required to resolve document names for build-time generation | ||
services.AddSingleton(new NamedService<OpenApiDocumentService>(documentName)); | ||
return services; | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.