Introdução a Microsoft.AspNetCore.OpenApi
O pacote Microsoft.AspNetCore.OpenApi
fornece suporte interno para a geração de documentos OpenAPI no ASP.NET Core. O pacote :
- É compatível com o AoT nativo.
- Aproveita o JSsuporte ao esquema ON fornecido por
System.Text.Json
. - Fornece uma API de transformadores para modificar documentos gerados.
- Dá suporte ao gerenciamento de vários documentos OpenAPI em um único aplicativo.
Instalação do pacote
Instalar o pacote Microsoft.AspNetCore.OpenApi
:
Execute o seguinte comando no Console do Gerenciador de Pacotes:
Install-Package Microsoft.AspNetCore.OpenApi -IncludePrerelease
Configurar a geração de documentos OpenAPI
O seguinte código:
- Adiciona serviços OpenAPI.
- Habilita o ponto de extremidade para exibir o documento OpenAPI no formato JSON.
var builder = WebApplication.CreateBuilder();
builder.Services.AddOpenApi();
var app = builder.Build();
app.MapOpenApi();
app.MapGet("/", () => "Hello world!");
app.Run();
Inicie o aplicativo e navegue até https://localhost:<port>/openapi/v1.json
para exibir o documento OpenAPI gerado.
A importância dos nomes de documentos
Cada documento OpenAPI em um aplicativo tem um nome exclusivo. O nome do documento padrão registrado é v1
.
builder.Services.AddOpenApi(); // Document name is v1
Para modificar o nome do documento, passe o nome como um parâmetro para a chamada AddOpenApi
.
builder.Services.AddOpenApi("internal"); // Document name is internal
O nome do documento aparece em vários locais na implementação do OpenAPI.
Ao buscar o documento OpenAPI gerado, o nome do documento é fornecido como o argumento de parâmetro documentName
na solicitação. As solicitações a seguir resolvem os documentos v1
e internal
.
GET http://localhost:5000/openapi/v1.json
GET http://localhost:5000/openapi/internal.json
Opções para personalizar a geração de documentos OpenAPI
As seções a seguir demonstram como personalizar a geração de documentos OpenAPI.
Personalizar a versão do OpenAPI de um documento gerado
Por padrão, a geração de documentos OpenAPI cria um documento compatível com a v3.0 da especificação OpenAPI. O código a seguir demonstra como modificar a versão padrão do documento OpenAPI:
builder.Services.AddOpenApi(options =>
{
options.OpenApiVersion = OpenApiSpecVersion.OpenApi2_0;
});
Personalizar a rota do ponto de extremidade OpenAPI
Por padrão, o ponto de extremidade OpenAPI registrado por meio de uma chamada para MapOpenApi
expõe o documento no ponto de extremidade /openapi/{documentName}.json
. O código a seguir demonstra como personalizar a rota na qual o documento OpenAPI está registrado:
app.MapOpenApi("/openapi/{documentName}/openapi.json");
Observação: é possível, mas não recomendado, remover o parâmetro de rota documentName
da rota do ponto de extremidade. Quando o parâmetro de rota documentName
é removido da rota do ponto de extremidade, a estrutura tenta resolver o nome do documento a partir do parâmetro de consulta. Não fornecer o documentName
na rota ou na consulta pode resultar em um comportamento inesperado.
Personalizar o ponto de extremidade OpenAPI
Como o documento OpenAPI é servido por meio de um ponto de extremidade do manipulador de rota, qualquer personalização disponível para ponto de extremidade mínimos padrão estará disponível para o ponto de extremidade OpenAPI.
Personalizar pontos de extremidade OpenAPI com metadados de ponto de extremidade
A lista a seguir mostra os metadados de ponto de extremidade que é usado para personalizar o documento OpenAPI gerado:
- Resumos de IEndpointSummaryMetadata
- Descrições de IEndpointDescriptionMetadata
- Corpo da solicitação de IAcceptsMetadata
- Informações de resposta do IProducesResponseTypeMetadata
- IDs de operação de IEndpointNameMetadata
- Marcas OpenAPI de ITagsMetadata
Para saber mais sobre como personalizar o documento OpenAPI gerado modificando metadados de ponto de extremidade, consulte Como usar o OpenAPI em aplicativos de API mínimos.
Limitar o acesso a documentos OpenAPI a usuários autorizados
O ponto de extremidade OpenAPI não permite nenhuma verificação de autorização por padrão. No entanto, é possível limitar o acesso ao documento OpenAPI. Por exemplo, no código a seguir, o acesso ao documento OpenAPI é limitado àqueles com a função tester
:
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder();
builder.Services.AddAuthentication().AddJwtBearer();
builder.Services.AddAuthorization(o =>
{
o.AddPolicy("ApiTesterPolicy", b => b.RequireRole("tester"));
});
builder.Services.AddOpenApi();
var app = builder.Build();
app.MapOpenApi()
.RequireAuthorization("ApiTesterPolicy");
app.MapGet("/", () => "Hello world!");
app.Run();
Documento OpenAPI gerado pelo cache
O documento OpenAPI é gerado novamente sempre que uma solicitação ao ponto de extremidade OpenAPI é enviada. A regeneração permite que os transformadores incorporem o estado dinâmico do aplicativo em sua operação. Por exemplo, regenerar uma solicitação com detalhes do contexto HTTP. Quando aplicável, o documento OpenAPI pode ser armazenado em cache para evitar a execução do pipeline de geração de documentos em cada solicitação HTTP.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder();
builder.Services.AddOutputCache(options =>
{
options.AddBasePolicy(policy => policy.Expire(TimeSpan.FromMinutes(10)));
});
builder.Services.AddOpenApi();
var app = builder.Build();
app.UseOutputCache();
app.MapOpenApi()
.CacheOutput();
app.MapGet("/", () => "Hello world!");
app.Run();
Transformadores de documento OpenAPI
Esta seção demonstra como personalizar documentos OpenAPI com transformadores.
Personalizar documentos OpenAPI com transformadores
Os transformadores fornecem uma API para modificar o documento OpenAPI com personalizações definidas pelo usuário. Transformadores são úteis para cenários como:
- Adicionar parâmetros a todas as operações em um documento.
- Modificar descrições para parâmetros ou operações.
- Adicionar informações de nível superior ao documento OpenAPI.
Os transformadores se enquadram em duas categorias:
- Os transformadores de documento têm acesso a todo o documento OpenAPI. Eles podem ser usados para fazer modificações globais no documento.
- Os transformadores de operação se aplicam a cada operação individual. Cada operação individual é uma combinação de caminho e método HTTP. Elas podem ser usadas para modificar parâmetros ou respostas em pontos de extremidade.
Os transformadores podem ser registrados no documento por meio da chamada UseTransformer
no objeto OpenApiOptions
. O seguinte trecho de código mostra diferentes maneiras de registrar transformadores no documento:
- Registre um transformador de documento usando um delegado.
- Registre um transformador de documento usando uma instância de
IOpenApiDocumentTransformer
. - Registre um transformador de documento usando um
IOpenApiDocumentTransformer
ativado por DI. - Registrar um transformador de operação usando um delegado.
using Microsoft.AspNetCore.OpenApi;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder();
builder.Services.AddOpenApi(options =>
{
options.UseTransformer((document, context, cancellationToken)
=> Task.CompletedTask);
options.UseTransformer(new MyDocumentTransformer());
options.UseTransformer<MyDocumentTransformer>();
options.UseOperationTransformer((operation, context, cancellationToken)
=> Task.CompletedTask);
});
var app = builder.Build();
app.MapOpenApi();
app.MapGet("/", () => "Hello world!");
app.Run();
Ordem de execução para transformadores
Os transformadores são executados na ordem "primeiro a entrar, primeiro a sair" com base no registro. No trecho de código a seguir, o transformador de documento tem acesso às modificações feitas pelo transformador de operação:
var builder = WebApplication.CreateBuilder();
builder.Services.AddOpenApi(options =>
{
options.UseOperationTransformer((operation, context, cancellationToken)
=> Task.CompletedTask);
options.UseTransformer((document, context, cancellationToken)
=> Task.CompletedTask);
});
var app = builder.Build();
app.MapOpenApi();
app.MapGet("/", () => "Hello world!");
app.Run();
Usar transformadores de documento
Os transformadores de documento têm acesso a um objeto de contexto que inclui:
- O nome do documento que está sendo modificado.
- A lista de
ApiDescriptionGroups
associados a esse documento. - O
IServiceProvider
usado na geração de documentos.
Os transformadores de documento também podem alterar o documento OpenAPI gerado. O exemplo a seguir demonstra um transformador de documento que adiciona algumas informações sobre a API ao documento OpenAPI.
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Builder;
var builder = WebApplication.CreateBuilder();
builder.Services.AddOpenApi(options =>
{
options.UseTransformer((document, context, cancellationToken) =>
{
document.Info = new()
{
Title = "Checkout API",
Version = "v1",
Description = "API for processing checkouts from cart."
};
return Task.CompletedTask;
});
});
var app = builder.Build();
app.MapOpenApi();
app.MapGet("/", () => "Hello world!");
app.Run();
Os transformadores de documento ativados pelo serviço podem utilizar instâncias de DI para modificar o aplicativo. O exemplo a seguir demonstra um transformador de documento que usa o serviço IAuthenticationSchemeProvider
da camada de autenticação. Ele verifica se algum esquema relacionado ao portador JWT está registrado no aplicativo e os adiciona ao nível superior do documento OpenAPI:
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder();
builder.Services.AddAuthentication().AddJwtBearer();
builder.Services.AddOpenApi(options =>
{
options.UseTransformer<BearerSecuritySchemeTransformer>();
});
var app = builder.Build();
app.MapOpenApi();
app.MapGet("/", () => "Hello world!");
app.Run();
internal sealed class BearerSecuritySchemeTransformer(IAuthenticationSchemeProvider authenticationSchemeProvider) : IOpenApiDocumentTransformer
{
public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken)
{
var authenticationSchemes = await authenticationSchemeProvider.GetAllSchemesAsync();
if (authenticationSchemes.Any(authScheme => authScheme.Name == "Bearer"))
{
var requirements = new Dictionary<string, OpenApiSecurityScheme>
{
["Bearer"] = new OpenApiSecurityScheme
{
Type = SecuritySchemeType.Http,
Scheme = "bearer", // "bearer" refers to the header name here
In = ParameterLocation.Header,
BearerFormat = "Json Web Token"
}
};
document.Components ??= new OpenApiComponents();
document.Components.SecuritySchemes = requirements;
}
}
}
Os transformadores de documento são exclusivos da instância do documento à qual estão associados. No exemplo a seguir, um transformador:
- Registra requisitos relacionados à autenticação no documento
internal
. - Deixa o documento
public
não modificado.
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder();
builder.Services.AddAuthentication().AddJwtBearer();
builder.Services.AddOpenApi("internal", options =>
{
options.UseTransformer<BearerSecuritySchemeTransformer>();
});
builder.Services.AddOpenApi("public");
var app = builder.Build();
app.MapOpenApi();
app.MapGet("/world", () => "Hello world!")
.WithGroupName("internal");
app.MapGet("/", () => "Hello universe!")
.WithGroupName("public");
app.Run();
internal sealed class BearerSecuritySchemeTransformer(IAuthenticationSchemeProvider authenticationSchemeProvider) : IOpenApiDocumentTransformer
{
public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken)
{
var authenticationSchemes = await authenticationSchemeProvider.GetAllSchemesAsync();
if (authenticationSchemes.Any(authScheme => authScheme.Name == "Bearer"))
{
// Add the security scheme at the document level
var requirements = new Dictionary<string, OpenApiSecurityScheme>
{
["Bearer"] = new OpenApiSecurityScheme
{
Type = SecuritySchemeType.Http,
Scheme = "bearer", // "bearer" refers to the header name here
In = ParameterLocation.Header,
BearerFormat = "Json Web Token"
}
};
document.Components ??= new OpenApiComponents();
document.Components.SecuritySchemes = requirements;
// Apply it as a requirement for all operations
foreach (var operation in document.Paths.Values.SelectMany(path => path.Operations))
{
operation.Value.Security.Add(new OpenApiSecurityRequirement
{
[new OpenApiSecurityScheme { Reference = new OpenApiReference { Id = "Bearer", Type = ReferenceType.SecurityScheme } }] = Array.Empty<string>()
});
}
}
}
}
Usar transformadores de operação
As operações são combinações exclusivas de métodos e caminhos HTTP em um documento OpenAPI. Os transformadores de operação são úteis quando uma modificação:
- Deve ser feita para cada ponto de extremidade em um aplicativo ou
- Aplicada condicionalmente a determinadas rotas.
Os transformadores de operação têm acesso a um objeto de contexto que contém:
- O nome do documento ao qual a operação pertence.
- O
ApiDescription
associado à operação. - O
IServiceProvider
usado na geração de documentos.
Por exemplo, o transformador de operação a seguir adiciona 500
como um código de status de resposta compatível com todas as operações no documento.
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder();
builder.Services.AddAuthentication().AddJwtBearer();
builder.Services.AddOpenApi(options =>
{
options.UseOperationTransformer((operation, context, cancellationToken) =>
{
operation.Responses.Add("500", new OpenApiResponse { Description = "Internal server error" });
return Task.CompletedTask;
});
});
var app = builder.Build();
app.MapOpenApi();
app.MapGet("/", () => "Hello world!");
app.Run();
Usar o documento OpenAPI gerado
Os documentos OpenAPI podem se conectar a um amplo ecossistema de ferramentas existentes para teste, documentação e desenvolvimento local.
Usar a interface do usuário do Swagger para testes ad hoc locais
Por padrão, o pacote Microsoft.AspNetCore.OpenApi
não é fornecido com suporte interno para visualizar ou interagir com o documento OpenAPI. Ferramentas populares para visualizar ou interagir com o documento OpenAPI incluem a interface do usuário do Swagger e o ReDoc. A interface do usuário do Swagger e o ReDoc podem ser integrados em um aplicativo de várias maneiras. Os editores como o Visual Studio e o VS Code oferecem extensões e experiências internas para teste em um documento OpenAPI.
O pacote Swashbuckle.AspNetCore.SwaggerUi
fornece um pacote de ativos da Web da interface do usuário do Swagger para uso em aplicativos. Esse pacote pode ser usado para renderizar uma interface do usuário para o documento gerado. Para configurar isso, instale o pacote Swashbuckle.AspNetCore.SwaggerUi
.
Habilite o middleware swagger-ui com uma referência à rota OpenAPI registrada anteriormente. Para limitar a divulgação de informações e a vulnerabilidade de segurança, habilite apenas a interface do usuário do Swagger em ambientes de desenvolvimento.
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder();
builder.Services.AddOpenApi();
var app = builder.Build();
app.MapOpenApi();
if (app.Environment.IsDevelopment())
{
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("/openapi/v1.json", "v1");
});
}
app.MapGet("/", () => "Hello world!");
app.Run();
Usando Escalar para documentação de API interativa
Escalar é uma UI de documento interativo de código aberto para OpenAPI. Scalar pode ser integrado ao ponto de extremidade OpenAPI fornecido pelo ASP.NET Core. Para configurar o Scalar, instale o pacote Scalar.AspNetCore
.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
using Scalar.AspNetCore;
var builder = WebApplication.CreateBuilder();
builder.Services.AddOpenApi();
var app = builder.Build();
app.MapOpenApi();
if (app.Environment.IsDevelopment())
{
app.MapScalarApiReference();
}
app.MapGet("/", () => "Hello world!");
app.Run();
Executar lint de documentos OpenAPI gerados com Spectral
Spectral é um linter de documento OpenAPI de código aberto. O Spectral pode ser incorporado ao build do aplicativo para verificar a qualidade dos documentos OpenAPI gerados. Instale o Spectral de acordo com as instruções de instalação do pacote.
Para aproveitar o Spectral, instale o pacote Microsoft.Extensions.ApiDescription.Server
para habilitar a geração de documentos OpenAPI no tempo do build.
Habilite a geração de documentos em tempo de build definindo as seguintes propriedades no arquivo .csproj
do aplicativo”:
<PropertyGroup>
<OpenApiDocumentsDirectory>$(MSBuildProjectDirectory)</OpenApiDocumentsDirectory>
<OpenApiGenerateDocuments>true</OpenApiGenerateDocuments>
</PropertyGroup>
Execute dotnet build
para gerar o documento.
dotnet build
Crie um arquivo .spectral.yml
com o conteúdo a seguir.
extends: ["spectral:oas"]
Depois, execute spectral lint
no arquivo gerado.
spectral lint WebMinOpenApi.json
...
The output shows any issues with the OpenAPI document.
```output
1:1 warning oas3-api-servers OpenAPI "servers" must be present and non-empty array.
3:10 warning info-contact Info object must have "contact" object. info
3:10 warning info-description Info "description" must be present and non-empty string. info
9:13 warning operation-description Operation "description" must be present and non-empty string. paths./.get
9:13 warning operation-operationId Operation must have "operationId". paths./.get
✖ 5 problems (0 errors, 5 warnings, 0 infos, 0 hints)
Comentários
https://aka.ms/ContentUserFeedback.
Em breve: Ao longo de 2024, eliminaremos os problemas do GitHub como o mecanismo de comentários para conteúdo e o substituiremos por um novo sistema de comentários. Para obter mais informações, consulteEnviar e exibir comentários de