openapi
Skill808 starsChanged 4 months agoMITView on GitHub
Built-in OpenAPI support for .NET 10 applications. Covers document generation, transformers, TypedResults metadata, security schemes, XML comments, build-time generation, and multiple document support. No Swashbuckle needed. Load this skill when setting up API documentation, customizing OpenAPI output, adding security schemes to docs, or when the user mentions "OpenAPI", "AddOpenApi", "MapOpenApi", "document transformer", "operation transformer", "schema transformer", "OpenAPI 3.1", "API documentation", "Swashbuckle replacement", "Produces", "WithSummary", "WithDescription", "ProblemDetails", "Kiota", or "client generation".
13 other projects use a version of this.
Adopted by
Most recently taken up by
- AnyOrgName/php-skillstheir own version, first seen Nov 8, 2026
- jars-demo/jars-skillstheir own version, first seen Oct 25, 2026
- DeepSpaceCartel/skillstheir own version, first seen Oct 25, 2026
- Resgrid/Coreword for word, first seen Oct 8, 2026
- PyGithub/PyGithubtheir own version, first seen Oct 8, 2026
- flexprice/flexpricetheir own version, first seen Oct 8, 2026
Other versions13 projects use a version of this.
Word for word · 1
- Resgrid/Core★ 238100% same
Edited · 0
None found.
Wrote their own version · 12
- PyGithub/PyGithub★ 7.8ksame name
- flexprice/flexprice★ 6.9ksame name
- AnyOrgName/php-skills★ 4same name
- jkaninda/okapi-skills★ 3same name
- DeepSpaceCartel/skills★ 2same name
- ffsshhttiikk/opencode-agents-skills★ 2same name
- batur/ts-baseline-docs★ 1same name
- mgoericke/claude-skills-devcontainer★ 1same name
- ScaleDockHQ/scaledock-skills★ 1same name
- evgyur/hermes-openapi-skill★ 0same name
2 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository57 other files it gives its agents.
- AGENTS.mdAGENTS.md
- .claude/rules/agents.mdAGENTS.md
- .codex/AGENTS.mdAGENTS.md
- .opencode/AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- .cursor/rules/dotnet-rules.mdCursor rule
- api-versioningSkill
- arch-checkSkill
- architecture-advisorSkill
- aspireSkill
- authenticationSkill
- avaloniaSkill
- build-fixSkill
- cachingSkill
- checkpointSkill
- ci-cdSkill
- clean-architectureSkill
- code-reviewSkill
- configurationSkill
- console-cliSkill
- container-publishSkill
- convention-learnerSkill
- dddSkill
- dependency-injectionSkill
- desktop-mvvmSkill
- de-sloppifySkill
- dockerSkill
- dotnet-initSkill
- ef-coreSkill
- error-handlingSkill
- health-checkSkill
- httpclient-factorySkill
- instinct-systemSkill
- loggingSkill
- messagingSkill
- migrateSkill
- minimal-apiSkill
- modern-csharpSkill
- native-aotSkill
- opentelemetrySkill
- outdatedSkill
- planSkill
- project-setupSkill
- project-structureSkill
- resilienceSkill
- scaffoldSkill
- scalarSkill
- security-scanSkill
- serilogSkill
- specSkill
- tddSkill
- testingSkill
- token-reportSkill
- verifySkill
- vertical-sliceSkill
- workflow-masterySkill
- wrap-upSkill
The file
Files
OpenAPI
Core Principles
- Built-in, not Swashbuckle — .NET 10 ships
Microsoft.AspNetCore.OpenApias the official, framework-maintained OpenAPI solution. Swashbuckle was removed from templates in .NET 9 and is no longer recommended. - TypedResults drive the schema —
TypedResults.Ok<T>()automatically generates correct OpenAPI response schemas.Results.Ok()does not. Always useTypedResults. - Transformers over workarounds — Document, operation, and schema transformers compose cleanly. Use them for security schemes, global responses, and schema customization.
- Metadata on every endpoint — Use
.WithName(),.WithSummary(),.WithTags()on every endpoint. This metadata feeds directly into the OpenAPI spec and client generators.
Patterns
Basic Setup
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenApi();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.MapOpenApi(); // Serves at /openapi/v1.json
}Endpoint Metadata
group.MapPost("/", CreateOrder)
.WithName("CreateOrder")
.WithSummary("Create a new order")
.WithDescription("Creates a new order for the specified customer.")
.Produces<OrderResponse>(StatusCodes.Status201Created)
.ProducesValidationProblem()
.ProducesProblem(StatusCodes.Status500InternalServerError);With TypedResults, response metadata is inferred automatically:
static async Task<Results<Created<OrderResponse>, ValidationProblem>> CreateOrder(
CreateOrderRequest request, ISender sender, CancellationToken ct)
{
var result = await sender.Send(new CreateOrder.Command(request), ct);
return result.IsSuccess
? TypedResults.Created($"/api/orders/{result.Value.Id}", result.Value)
: TypedResults.ValidationProblem(result.Errors);
}Bearer Token Security Scheme
builder.Services.AddOpenApi(options =>
{
options.AddDocumentTransformer<BearerSecuritySchemeTransformer>();
});
internal sealed class BearerSecuritySchemeTransformer(
IAuthenticationSchemeProvider authSchemeProvider) : IOpenApiDocumentTransformer
{
public async Task TransformAsync(OpenApiDocument document,
OpenApiDocumentTransformerContext context, CancellationToken ct)
{
var schemes = await authSchemeProvider.GetAllSchemesAsync();
if (!schemes.Any(s => s.Name == "Bearer"))
return;
document.Components ??= new OpenApiComponents();
document.Components.SecuritySchemes = new Dictionary<string, IOpenApiSecurityScheme>
{
["Bearer"] = new OpenApiSecurityScheme
{
Type = SecuritySchemeType.Http,
Scheme = "bearer",
BearerFormat = "JWT",
In = ParameterLocation.Header
}
};
foreach (var operation in document.Paths.Values.SelectMany(p => p.Operations))
{
operation.Value.Security ??= [];
operation.Value.Security.Add(new OpenApiSecurityRequirement
{
[new OpenApiSecuritySchemeReference("Bearer", document)] = []
});
}
}
}Document Info Transformer
builder.Services.AddOpenApi(options =>
{
options.AddDocumentTransformer((document, context, ct) =>
{
document.Info = new()
{
Title = "Checkout API",
Version = "v1",
Description = "API for processing orders and payments."
};
return Task.CompletedTask;
});
});Multiple OpenAPI Documents
builder.Services.AddOpenApi("v1");
builder.Services.AddOpenApi("internal", options =>
{
options.AddDocumentTransformer<BearerSecuritySchemeTransformer>();
});
// Endpoints choose their document via WithGroupName
app.MapGet("/public", () => "Hello").WithGroupName("v1");
app.MapGet("/admin", () => "Secret").WithGroupName("internal");Endpoints without .WithGroupName() appear in all documents.
XML Documentation Comments (.NET 10)
Enable in the project file — the source generator extracts <summary>, <param>, <response> tags automatically:
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>/// <summary>Retrieves a project board by ID.</summary>
/// <param name="id">The project board ID.</param>
/// <response code="200">Returns the project board.</response>
/// <response code="404">Board not found.</response>
static async Task<Results<Ok<Board>, NotFound>> GetBoard(int id, AppDbContext db)
{
var board = await db.Boards.FindAsync(id);
return board is not null ? TypedResults.Ok(board) : TypedResults.NotFound();
}XML comments on lambdas are not captured by the compiler. Use named methods.
Schema Transformer
options.AddSchemaTransformer((schema, context, ct) =>
{
if (context.JsonTypeInfo.Type == typeof(decimal))
{
schema.Format = "decimal";
}
return Task.CompletedTask;
});Per-Endpoint Operation Transformer (.NET 10)
app.MapGet("/old", () => "deprecated")
.AddOpenApiOperationTransformer((operation, context, ct) =>
{
operation.Deprecated = true;
return Task.CompletedTask;
});Build-Time Document Generation
<PackageReference Include="Microsoft.Extensions.ApiDescription.Server" Version="*" />
<PropertyGroup>
<OpenApiDocumentsDirectory>.</OpenApiDocumentsDirectory>
</PropertyGroup>The spec file is generated in the output directory during build.
YAML Endpoint (.NET 10)
app.MapOpenApi("/openapi/{documentName}.yaml");Anti-patterns
Don't Use Swashbuckle for New Projects
// BAD — removed from .NET 9+ templates, maintenance concerns
builder.Services.AddSwaggerGen();
app.UseSwagger();
app.UseSwaggerUI();
// GOOD — built-in OpenAPI
builder.Services.AddOpenApi();
app.MapOpenApi();Don't Use WithOpenApi() in .NET 10
// BAD — deprecated, produces ASPDEPR002 warning
app.MapGet("/", () => "hello").WithOpenApi(op => { op.Deprecated = true; return op; });
// GOOD — use per-endpoint operation transformer
app.MapGet("/", () => "hello")
.AddOpenApiOperationTransformer((op, ctx, ct) =>
{
op.Deprecated = true;
return Task.CompletedTask;
});Don't Use Untyped Results
// BAD — Results.Ok doesn't contribute to OpenAPI schema
static async Task<IResult> GetOrder(Guid id, AppDbContext db)
{
var order = await db.Orders.FindAsync(id);
return order is not null ? Results.Ok(order) : Results.NotFound();
}
// GOOD — TypedResults with union return type
static async Task<Results<Ok<Order>, NotFound>> GetOrder(Guid id, AppDbContext db)
{
var order = await db.Orders.FindAsync(id);
return order is not null ? TypedResults.Ok(order) : TypedResults.NotFound();
}Don't Skip WithName on Endpoints
// BAD — client generators produce poor method names without operationId
group.MapGet("/{id:guid}", GetOrder);
// GOOD — operationId feeds into generated client method names
group.MapGet("/{id:guid}", GetOrder).WithName("GetOrder");Don't Use OpenApiAny in .NET 10
// BAD — OpenApiAny types removed in Microsoft.OpenApi v2.x
schema.Example = new OpenApiString("2025-01-01");
// GOOD — use JsonNode from System.Text.Json.Nodes
schema.Example = JsonValue.Create("2025-01-01");Decision Guide
| Scenario | Recommendation |
| New API project | AddOpenApi() + MapOpenApi() (built-in) |
| API documentation UI | Scalar (MapScalarApiReference()) |
| Security schemes in docs | Document transformer with IOpenApiDocumentTransformer |
| Response documentation | TypedResults with union return types |
| XML doc integration | <GenerateDocumentationFile>true</GenerateDocumentationFile> |
| Multiple API versions | Multiple AddOpenApi("v1") calls + WithGroupName() |
| Client code generation | Kiota (Microsoft recommended) or NSwag |
| Build-time spec | Microsoft.Extensions.ApiDescription.Server package |
| OpenAPI version | 3.1 (default in .NET 10), force 3.0 if consumers require it |
| Per-endpoint customization | .AddOpenApiOperationTransformer() on the endpoint |
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

