« Swagger » : différence entre les versions
De Banane Atomic
Aller à la navigationAller à la recherche
(→Test) |
|||
(34 versions intermédiaires par le même utilisateur non affichées) | |||
Ligne 4 : | Ligne 4 : | ||
* [https://docs.microsoft.com/en-us/aspnet/core/tutorials/getting-started-with-nswag?view=aspnetcore-2.1&tabs=visual-studio-code%2Cvisual-studio-xml Get started with NSwag and ASP.NET Core] | * [https://docs.microsoft.com/en-us/aspnet/core/tutorials/getting-started-with-nswag?view=aspnetcore-2.1&tabs=visual-studio-code%2Cvisual-studio-xml Get started with NSwag and ASP.NET Core] | ||
= | = [https://docs.microsoft.com/en-us/aspnet/core/tutorials/getting-started-with-nswag?tabs=netcore-cli NSwag] = | ||
== Installation == | |||
<kode lang='powershell'> | <kode lang='powershell'> | ||
# pour vscode | # pour vscode | ||
dotnet add | dotnet add package NSwag.AspNetCore | ||
# | # Add to the project file *.csproj: | ||
# <ItemGroup> | # <ItemGroup> | ||
# <PackageReference Include="NSwag.AspNetCore" Version="11.17.15" /> | # <PackageReference Include="NSwag.AspNetCore" Version="11.17.15" /> | ||
</kode> | </kode> | ||
= [https://docs.microsoft.com/en-us/aspnet/core/tutorials/getting-started-with-nswag?tabs=netcore-cli#add-and-configure-swagger-middleware Configuration] = | == [https://docs.microsoft.com/en-us/aspnet/core/tutorials/getting-started-with-nswag?tabs=netcore-cli#add-and-configure-swagger-middleware Configuration] == | ||
== Configuration Web API == | === Configuration Web API === | ||
<filebox fn=' | <filebox fn='Program.cs'> | ||
builder.Services.AddSwaggerDocument(configuration => | |||
{ | { | ||
configuration.Title = "MyApp"; | |||
configuration.Version = typeof(Program).Assembly.GetSimplifiedVersion(); | |||
}); | |||
if (app.Environment.IsDevelopment()) | |||
{ | { | ||
app.UseOpenApi(); | app.UseOpenApi(); | ||
app.UseSwaggerUi3(); | app.UseSwaggerUi3(); | ||
} | |||
</filebox> | </filebox> | ||
== Configuration MVC == | === Configuration MVC === | ||
<filebox fn='Startup.cs' collapsed> | <filebox fn='Startup.cs' collapsed> | ||
using NJsonSchema; | using NJsonSchema; | ||
Ligne 63 : | Ligne 65 : | ||
</filebox> | </filebox> | ||
= Problème avec IActionResult = | == Problème avec IActionResult == | ||
{{boxx|NSwag}} utilise la réflexion pour obtenir le type de retour. Avec {{boxx|IActionResult}} il ne peut pas. | {{boxx|NSwag}} utilise la réflexion pour obtenir le type de retour. Avec {{boxx|IActionResult}} il ne peut pas. | ||
<kode lang='csharp'> | <kode lang='csharp'> | ||
Ligne 75 : | Ligne 77 : | ||
</kode> | </kode> | ||
= | = [https://docs.microsoft.com/en-us/aspnet/core/tutorials/getting-started-with-swashbuckle?view=aspnetcore-5.0&tabs=visual-studio-code Swashbuckle] = | ||
== Swashbuckle installation == | |||
Already installed in .NET 7+ | |||
<filebox fn='MyWebApi.csproj' lang='xml'> | |||
<ItemGroup> | |||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" /> | |||
</ItemGroup> | |||
</filebox> | |||
<filebox fn='Program.cs'> | |||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle | |||
builder.Services.AddEndpointsApiExplorer(); | |||
builder.Services.AddSwaggerGen(); | |||
if (app.Environment.IsDevelopment()) | |||
{ | |||
app.UseSwagger() | |||
.UseSwaggerUI(); | |||
} | |||
</filebox> | |||
== Installation Old == | |||
<kode lang='bash'> | |||
dotnet add package Swashbuckle.AspNetCore | |||
</kode> | |||
<filebox fn='Startup.cs'> | |||
public void ConfigureServices(IServiceCollection services) | |||
{ | |||
services.AddControllers(); | |||
services.AddSwaggerGen(c => | |||
{ | |||
c.SwaggerDoc("v1", new OpenApiInfo { Title = "EFWebApi", Version = "v1" }); | |||
}); | |||
} | |||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) | |||
{ | |||
if (env.IsDevelopment()) | |||
{ | |||
app.UseDeveloperExceptionPage(); | |||
app.UseSwagger(); | |||
app.UseSwaggerUI(c => | |||
{ | |||
c.SwaggerEndpoint("/swagger/v1/swagger.json", "EFWebApi v1"); | |||
c.RoutePrefix = string.Empty; // serve the Swagger UI at the app's root (http://localhost:<port>/) | |||
}); | |||
} | |||
</filebox> | |||
== Usage == | |||
<filebox fn='Controllers/ItemController.cs'> | |||
[ApiController] | |||
[Route("[controller]")] | |||
[Produces("application/json")] // set the Media type | |||
public class ItemController : ControllerBase | |||
{ | |||
[HttpGet] | |||
[ProducesResponseType(typeof(IEnumerable<Item>), StatusCodes.Status200OK)] // set the status code and the return type | |||
public IActionResult Get() { /* ... */ } | |||
} | |||
</filebox> | |||
== [https://learn.microsoft.com/en-us/aspnet/core/tutorials/getting-started-with-swashbuckle?view=aspnetcore-7.0&tabs=visual-studio-code#xml-comments XML documentation] == | |||
<filebox fn='MyProject.csproj' lang='xml'> | |||
<PropertyGroup> | |||
<GenerateDocumentationFile>true</GenerateDocumentationFile> | |||
</PropertyGroup> | |||
</filebox> | |||
<filebox fn='Program.cs'> | |||
builder.Services.AddSwaggerGen( | |||
options => | |||
{ | |||
c.SwaggerDoc("v1", new OpenApiInfo { Title = "My Web Api", Version = "v1" }); | |||
// Set the comments path for the Swagger JSON and UI. | |||
var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; | |||
options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename)); | |||
}); | |||
} | |||
</filebox> | |||
<filebox fn='Controllers/ItemController.cs'> | |||
/// <summary>Fetch all the items.</summary> | |||
/// <param name="cancellationToken"></param> | |||
/// <returns>All the items</returns> | |||
/// <remarks> | |||
/// Sample request: | |||
/// | |||
/// GET /item | |||
/// </remarks> | |||
/// <response code="200">Returns all the items.</response> | |||
[HttpGet] | |||
[Produces("text/json")] | |||
[ProducesResponseType(typeof(IEnumerable<Item>), StatusCodes.Status200OK)] | |||
public IActionResult GetAll() { /* ... */ } | |||
</filebox> | |||
== [https://medium.com/@celery_liu/asp-net-core-web-api-with-swagger-api-versioning-for-dotnet-8-c8ce2fd7808c Version] == | |||
* [[Asp.net_core_8_web_api#Version|ASP.NET Core Version]] | |||
<filebox fn='Program.cs'> | |||
builder.Services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>(); | |||
// nuget package Asp.Versioning.Mvc.ApiExplorer | |||
builder.Services | |||
.AddApiVersioning(/* ... */) | |||
.AddApiExplorer( | |||
options => | |||
{ | |||
options.GroupNameFormat = "'v'VVV"; | |||
options.SubstituteApiVersionInUrl = true; | |||
}); | |||
app.UseSwagger(); | |||
app.UseSwaggerUI( | |||
options => | |||
{ | |||
var descriptions = app.DescribeApiVersions(); | |||
foreach (var description in descriptions) | |||
options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant()); | |||
}); | |||
</filebox> | |||
<filebox fn='ConfigureSwaggerOptions.cs'> | |||
public class ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider) : IConfigureOptions<SwaggerGenOptions> | |||
{ | |||
public void Configure(SwaggerGenOptions options) | |||
{ | |||
foreach (var description in provider.ApiVersionDescriptions) | |||
{ | |||
options.SwaggerDoc(description.GroupName, CreateInfoForApiVersion(description)); | |||
} | |||
static OpenApiInfo CreateInfoForApiVersion(ApiVersionDescription description) | |||
=> new() | |||
{ | |||
Title = "Power Analytics Model Management API", | |||
Version = description.ApiVersion.ToString(), | |||
Description = "API Description." | |||
}; | |||
} | |||
} | |||
</filebox> | |||
== Document Filter == | |||
<filebox fn='Program.cs'> | |||
builder.Services.AddSwaggerGen(c => | |||
{ | |||
c.DocumentFilter<MyDocumentFilter>(); | |||
}); | |||
</filebox> | |||
= Ouvrir le navigateur sur swagger = | <filebox fn='MyDocumentFilter.cs'> | ||
public class MyDocumentFilter : IDocumentFilter | |||
{ | |||
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) | |||
{ | |||
// add new property | |||
swaggerDoc.Extensions.Add("propertyName", new OpenApiObject | |||
{ | |||
["propertyName"] = new OpenApiString("value"), | |||
["propertyName"] = new OpenApiArray | |||
{ | |||
{ new OpenApiString("value") } | |||
} | |||
} | |||
} | |||
} | |||
</filebox> | |||
=== [https://vrcode.medium.com/implement-health-check-in-dot-net-core-api-and-integrate-in-swagger-5b812601cb35 Add HealthChecks endpoint] === | |||
<filebox fn='Program.cs' collapsed> | |||
builder.Services.AddHealthChecks(); | |||
builder.Services.AddSwaggerGen(c => | |||
{ | |||
c.DocumentFilter<HealthChecksDocumentFilter>(); | |||
}); | |||
var app = builder.Build(); | |||
app.MapHealthChecks("/health"); | |||
</filebox> | |||
<filebox fn='HealthChecksDocumentFilter.cs' collapsed> | |||
public class HealthChecksDocumentFilter : IDocumentFilter | |||
{ | |||
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) | |||
{ | |||
var pathItem = new OpenApiPathItem(); | |||
var operation = new OpenApiOperation(); | |||
operation.Tags.Add(new OpenApiTag { Name = "ApiHealth" }); | |||
var properties = new Dictionary<string, OpenApiSchema> | |||
{ | |||
{ "status", new OpenApiSchema() { Type = "string" } }, | |||
{ "errors", new OpenApiSchema() { Type = "array" } } | |||
}; | |||
var response = new OpenApiResponse(); | |||
response.Content.Add("application/json", new OpenApiMediaType | |||
{ | |||
Schema = new OpenApiSchema | |||
{ | |||
Type = "object", | |||
AdditionalPropertiesAllowed = true, | |||
Properties = properties | |||
} | |||
}); | |||
operation.Responses.Add("200", response); | |||
pathItem.AddOperation(OperationType.Get, operation); | |||
swaggerDoc.Paths.Add("/health", pathItem); | |||
} | |||
} | |||
</filebox> | |||
== [https://docs.microsoft.com/en-us/aspnet/core/tutorials/getting-started-with-swashbuckle?view=aspnetcore-5.0&tabs=visual-studio-code#customize-the-ui Dark theme] == | |||
<filebox fn='Startup.cs'> | |||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) | |||
{ | |||
if (env.IsDevelopment()) | |||
{ | |||
app.UseDeveloperExceptionPage(); | |||
app.UseStaticFiles(); | |||
app.UseSwagger(); | |||
app.UseSwaggerUI(c => | |||
{ | |||
c.SwaggerEndpoint("/swagger/v1/swagger.json", "EFWebApi v1"); | |||
c.RoutePrefix = string.Empty; | |||
c.InjectStylesheet("/swagger-ui/dark-theme.css"); | |||
}); | |||
} | |||
</filebox> | |||
<filebox fn='wwwroot/swagger-ui/dark-theme.css' collapsed> | |||
.swagger-ui .topbar .download-url-wrapper .select-label select { | |||
border: 2px solid #89bf04;; | |||
} | |||
body { | |||
background-color: #303030; | |||
} | |||
.swagger-ui, | |||
.swagger-ui .info .title, | |||
.swagger-ui .opblock-tag, | |||
.swagger-ui section.models h4, | |||
.swagger-ui .opblock .opblock-summary-operation-id, | |||
.swagger-ui .opblock .opblock-summary-path, | |||
.swagger-ui .opblock .opblock-summary-path__deprecated, | |||
.swagger-ui table thead tr td, | |||
.swagger-ui table thead tr th, | |||
.swagger-ui .parameter__name, | |||
.swagger-ui .parameter__type, | |||
.swagger-ui .response-col_status, | |||
.swagger-ui .model-title, | |||
.swagger-ui .model, | |||
.swagger-ui .tab li { | |||
color: #f0f0f0; | |||
} | |||
.swagger-ui input[type="email"], | |||
.swagger-ui input[type="file"], | |||
.swagger-ui input[type="password"], | |||
.swagger-ui input[type="search"], | |||
.swagger-ui input[type="text"], | |||
.swagger-ui textarea { | |||
background: #303030; | |||
color: #f0f0f0; | |||
border: 1px solid gray; | |||
} | |||
.swagger-ui .opblock .opblock-section-header { | |||
background-color: #1b1b1b; | |||
} | |||
.swagger-ui .opblock .opblock-section-header h4, | |||
.swagger-ui .btn { | |||
color: #f0f0f0; | |||
} | |||
.swagger-ui input[disabled], .swagger-ui select[disabled], .swagger-ui textarea[disabled] { | |||
background-color: #303030; | |||
color: lightgray; | |||
} | |||
.swagger-ui select { | |||
background: #303030 url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="gray"><path d="M13.418 7.859a.695.695 0 01.978 0 .68.68 0 010 .969l-3.908 3.83a.697.697 0 01-.979 0l-3.908-3.83a.68.68 0 010-.969.695.695 0 01.978 0L10 11l3.418-3.141z"/></svg>') right 10px center no-repeat; | |||
color: #f0f0f0; | |||
} | |||
.swagger-ui .response-control-media-type--accept-controller select { | |||
border-color: #89bf04; | |||
} | |||
.swagger-ui .response-control-media-type__accept-message { | |||
color: #89bf04; | |||
} | |||
.arrow path { | |||
fill: gray; | |||
} | |||
.swagger-ui section.models .model-container { | |||
border: 1px solid #61affe; | |||
} | |||
.swagger-ui .model-toggle::after { | |||
background: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="gray"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg>') 50% no-repeat; | |||
} | |||
.swagger-ui .download-contents { | |||
width: unset; | |||
} | |||
</filebox> | |||
= Url = | |||
{| class="wikitable wtp wtmono1" | |||
! Url | |||
! Resource | |||
|- | |||
| <nowiki>http://localhost:<port>/swagger</nowiki> || swagger UI | |||
|- | |||
| <nowiki>http://localhost:<port>/swagger/v1/swagger.json</nowiki> || swagger json | |||
|} | |||
= [https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#starting-a-web-browser Ouvrir le navigateur sur swagger] = | |||
Dans un projet Web API avec Visual Studio Code, ouvrir le navigateur sur la page swagger. | Dans un projet Web API avec Visual Studio Code, ouvrir le navigateur sur la page swagger. | ||
<filebox fn='.vscode\launch.json'> | <filebox fn='.vscode\launch.json'> | ||
{ | { | ||
"launchBrowser": { | "configurations": [ | ||
{ | |||
"serverReadyAction": { | |||
"action": "openExternally", | |||
"pattern": "^\\s*Now listening on:\\s+(https?://\\S+)", | |||
"uriFormat": "%s/swagger" | |||
}, | |||
// autre solution | |||
"launchBrowser": { | |||
"enabled": true, | |||
"args": "${auto-detect-url}", | |||
"windows": { | |||
"command": "cmd.exe", | |||
"args": "/C start ${auto-detect-url}/swagger/index.html?url=/swagger/v1/swagger.json#!/Items" | |||
} | |||
} | |||
</filebox> | </filebox> | ||
= Paramètres optionnels = | = Paramètres optionnels = | ||
Swagger ne gère pas les paramètres optionnels s'ils font partie du chemin, il les considère comme des paramètres required. | Swagger ne gère pas les paramètres optionnels s'ils font partie du chemin, il les considère comme des paramètres required. |
Dernière version du 18 septembre 2024 à 14:49
Liens
NSwag
Installation
# pour vscode dotnet add package NSwag.AspNetCore # Add to the project file *.csproj: # <ItemGroup> # <PackageReference Include="NSwag.AspNetCore" Version="11.17.15" /> |
Configuration
Configuration Web API
Program.cs |
builder.Services.AddSwaggerDocument(configuration => { configuration.Title = "MyApp"; configuration.Version = typeof(Program).Assembly.GetSimplifiedVersion(); }); if (app.Environment.IsDevelopment()) { app.UseOpenApi(); app.UseSwaggerUi3(); } |
Configuration MVC
Startup.cs |
using NJsonSchema; using NSwag.AspNetCore; using System.Reflection; public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseMvc(); // à ajouter avant app.UseSpa app.UseSwaggerUi(typeof(Startup).GetTypeInfo().Assembly, settings => { settings.GeneratorSettings.DefaultPropertyNameHandling = PropertyNameHandling.CamelCase; settings.PostProcess = document => { //document.Info.Version = "v1"; document.Info.Title = "Test API"; document.Info.Description = "A simple ASP.NET Core web API"; //document.Info.TermsOfService = "None"; document.Info.Contact = new NSwag.SwaggerContact { Name = "Nicolas", //Email = string.Empty, //Url = "https://twitter.com/spboyer" }; /*document.Info.License = new NSwag.SwaggerLicense { Name = "Use under LICX", Url = "https://example.com/license" };*/ }; }); |
Problème avec IActionResult
NSwag utilise la réflexion pour obtenir le type de retour. Avec IActionResult il ne peut pas.
[HttpGet] // utiliser SwaggerResponse [SwaggerResponse(HttpStatusCode.OK, typeof(IReadOnlyList<ItemDto>))] [SwaggerResponse(HttpStatusCode.BadRequest, typeof(void))] // ou ProducesResponseType [ProducesResponseType(typeof(IReadOnlyList<ItemDto>), StatusCodes.Status200OK)] public IActionResult Get() |
Swashbuckle
Swashbuckle installation
Already installed in .NET 7+
MyWebApi.csproj |
<ItemGroup> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" /> </ItemGroup> |
Program.cs |
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); if (app.Environment.IsDevelopment()) { app.UseSwagger() .UseSwaggerUI(); } |
Installation Old
dotnet add package Swashbuckle.AspNetCore |
Startup.cs |
public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "EFWebApi", Version = "v1" }); }); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseSwagger(); app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "EFWebApi v1"); c.RoutePrefix = string.Empty; // serve the Swagger UI at the app's root (http://localhost:<port>/) }); } |
Usage
Controllers/ItemController.cs |
[ApiController] [Route("[controller]")] [Produces("application/json")] // set the Media type public class ItemController : ControllerBase { [HttpGet] [ProducesResponseType(typeof(IEnumerable<Item>), StatusCodes.Status200OK)] // set the status code and the return type public IActionResult Get() { /* ... */ } } |
XML documentation
MyProject.csproj |
<PropertyGroup> <GenerateDocumentationFile>true</GenerateDocumentationFile> </PropertyGroup> |
Program.cs |
builder.Services.AddSwaggerGen( options => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "My Web Api", Version = "v1" }); // Set the comments path for the Swagger JSON and UI. var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename)); }); } |
Controllers/ItemController.cs |
/// <summary>Fetch all the items.</summary> /// <param name="cancellationToken"></param> /// <returns>All the items</returns> /// <remarks> /// Sample request: /// /// GET /item /// </remarks> /// <response code="200">Returns all the items.</response> [HttpGet] [Produces("text/json")] [ProducesResponseType(typeof(IEnumerable<Item>), StatusCodes.Status200OK)] public IActionResult GetAll() { /* ... */ } |
Version
Program.cs |
builder.Services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>(); // nuget package Asp.Versioning.Mvc.ApiExplorer builder.Services .AddApiVersioning(/* ... */) .AddApiExplorer( options => { options.GroupNameFormat = "'v'VVV"; options.SubstituteApiVersionInUrl = true; }); app.UseSwagger(); app.UseSwaggerUI( options => { var descriptions = app.DescribeApiVersions(); foreach (var description in descriptions) options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant()); }); |
ConfigureSwaggerOptions.cs |
public class ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider) : IConfigureOptions<SwaggerGenOptions> { public void Configure(SwaggerGenOptions options) { foreach (var description in provider.ApiVersionDescriptions) { options.SwaggerDoc(description.GroupName, CreateInfoForApiVersion(description)); } static OpenApiInfo CreateInfoForApiVersion(ApiVersionDescription description) => new() { Title = "Power Analytics Model Management API", Version = description.ApiVersion.ToString(), Description = "API Description." }; } } |
Document Filter
Program.cs |
builder.Services.AddSwaggerGen(c => { c.DocumentFilter<MyDocumentFilter>(); }); |
MyDocumentFilter.cs |
public class MyDocumentFilter : IDocumentFilter { public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) { // add new property swaggerDoc.Extensions.Add("propertyName", new OpenApiObject { ["propertyName"] = new OpenApiString("value"), ["propertyName"] = new OpenApiArray { { new OpenApiString("value") } } } } } |
Add HealthChecks endpoint
Program.cs |
builder.Services.AddHealthChecks(); builder.Services.AddSwaggerGen(c => { c.DocumentFilter<HealthChecksDocumentFilter>(); }); var app = builder.Build(); app.MapHealthChecks("/health"); |
HealthChecksDocumentFilter.cs |
public class HealthChecksDocumentFilter : IDocumentFilter { public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) { var pathItem = new OpenApiPathItem(); var operation = new OpenApiOperation(); operation.Tags.Add(new OpenApiTag { Name = "ApiHealth" }); var properties = new Dictionary<string, OpenApiSchema> { { "status", new OpenApiSchema() { Type = "string" } }, { "errors", new OpenApiSchema() { Type = "array" } } }; var response = new OpenApiResponse(); response.Content.Add("application/json", new OpenApiMediaType { Schema = new OpenApiSchema { Type = "object", AdditionalPropertiesAllowed = true, Properties = properties } }); operation.Responses.Add("200", response); pathItem.AddOperation(OperationType.Get, operation); swaggerDoc.Paths.Add("/health", pathItem); } } |
Dark theme
Startup.cs |
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseStaticFiles(); app.UseSwagger(); app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "EFWebApi v1"); c.RoutePrefix = string.Empty; c.InjectStylesheet("/swagger-ui/dark-theme.css"); }); } |
wwwroot/swagger-ui/dark-theme.css |
.swagger-ui .topbar .download-url-wrapper .select-label select { border: 2px solid #89bf04;; } body { background-color: #303030; } .swagger-ui, .swagger-ui .info .title, .swagger-ui .opblock-tag, .swagger-ui section.models h4, .swagger-ui .opblock .opblock-summary-operation-id, .swagger-ui .opblock .opblock-summary-path, .swagger-ui .opblock .opblock-summary-path__deprecated, .swagger-ui table thead tr td, .swagger-ui table thead tr th, .swagger-ui .parameter__name, .swagger-ui .parameter__type, .swagger-ui .response-col_status, .swagger-ui .model-title, .swagger-ui .model, .swagger-ui .tab li { color: #f0f0f0; } .swagger-ui input[type="email"], .swagger-ui input[type="file"], .swagger-ui input[type="password"], .swagger-ui input[type="search"], .swagger-ui input[type="text"], .swagger-ui textarea { background: #303030; color: #f0f0f0; border: 1px solid gray; } .swagger-ui .opblock .opblock-section-header { background-color: #1b1b1b; } .swagger-ui .opblock .opblock-section-header h4, .swagger-ui .btn { color: #f0f0f0; } .swagger-ui input[disabled], .swagger-ui select[disabled], .swagger-ui textarea[disabled] { background-color: #303030; color: lightgray; } .swagger-ui select { background: #303030 url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="gray"><path d="M13.418 7.859a.695.695 0 01.978 0 .68.68 0 010 .969l-3.908 3.83a.697.697 0 01-.979 0l-3.908-3.83a.68.68 0 010-.969.695.695 0 01.978 0L10 11l3.418-3.141z"/></svg>') right 10px center no-repeat; color: #f0f0f0; } .swagger-ui .response-control-media-type--accept-controller select { border-color: #89bf04; } .swagger-ui .response-control-media-type__accept-message { color: #89bf04; } .arrow path { fill: gray; } .swagger-ui section.models .model-container { border: 1px solid #61affe; } .swagger-ui .model-toggle::after { background: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="gray"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg>') 50% no-repeat; } .swagger-ui .download-contents { width: unset; } |
Url
Url | Resource |
---|---|
http://localhost:<port>/swagger | swagger UI |
http://localhost:<port>/swagger/v1/swagger.json | swagger json |
Dans un projet Web API avec Visual Studio Code, ouvrir le navigateur sur la page swagger.
.vscode\launch.json |
{ "configurations": [ { "serverReadyAction": { "action": "openExternally", "pattern": "^\\s*Now listening on:\\s+(https?://\\S+)", "uriFormat": "%s/swagger" }, // autre solution "launchBrowser": { "enabled": true, "args": "${auto-detect-url}", "windows": { "command": "cmd.exe", "args": "/C start ${auto-detect-url}/swagger/index.html?url=/swagger/v1/swagger.json#!/Items" } } |
Paramètres optionnels
Swagger ne gère pas les paramètres optionnels s'ils font partie du chemin, il les considère comme des paramètres required.