Skip to content

martincostello/openapi-extensions

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

OpenAPI Extensions for ASP.NET Core

NuGet NuGet Downloads

Build status codecov OpenSSF Scorecard

Introduction

A NuGet package of extensions for the Microsoft.AspNetCore.OpenApi package.

Features include:

  • Adding examples to OpenAPI operations and schemas.
  • Customizing descriptions for:
    • OpenAPI operation parameters and responses;
    • OpenAPI schemas and their properties.
  • Adding application URLs to the OpenAPI document.
  • Adding OpenAPI schema documentation from XML comments.
  • Adding an HTTP endpoint to get OpenAPI documents as YAML.

The library is also designed to be compatible with support for native AoT in ASP.NET Core 9.

A sample application using the library can be found here.

An overview of the library and how it works can be found on YouTube in this talk from .NET Conf 2024: 📺 Extending ASP.NET Core OpenAPI

Installation

To install the library from NuGet using the .NET SDK run the following command:

dotnet add package MartinCostello.OpenApi.Extensions

Usage

Below is an example code snippet showing how to use the features of the library:

using System.ComponentModel;
using System.Text.Json.Serialization;
using MartinCostello.OpenApi;
using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOpenApi((options) =>
{
    // Configure ASP.NET Core support for OpenAPI documentation...
});

builder.Services.AddOpenApiExtensions((options) =>
{
    // Always return the server URLs in the OpenAPI document
    // Only enable this option in production if you are sure
    // you wish to explicitly expose your server URLs.
    options.AddServerUrls = true;

    // Set a default URL to use for generation of the OpenAPI document using
    // https://www.nuget.org/packages/Microsoft.Extensions.ApiDescription.Server.
    options.DefaultServerUrl = "https://localhost:50001";

    // Add examples for OpenAPI operations and components
    options.AddExamples = true;

    // Add JSON serialization context to use to serialize examples when enabled
    options.SerializationContexts.Add(TodoJsonSerializerContext.Default);

    // Add a custom example provider for ProblemDetails
    options.AddExample<ProblemDetails, ProblemDetailsExampleProvider>();

    // Configure XML comments for the schemas in the OpenAPI document
    // from the assembly that the Program class is defined in.
    options.AddXmlComments<Program>();

    // Add a custom transformation for the descriptions in the OpenAPI document
    options.DescriptionTransformations.Add((p) => p.ToUpper());
});

// Required if AddServerUrls=true
builder.Services.AddHttpContextAccessor();

var app = builder.Build();

// Configure endpoint to get OpenAPI documents as JSON
app.MapOpenApi();

// Optionally also (or instead) configure endpoint to get OpenAPI documents as YAML
app.MapOpenApiYaml();

// The [Description] attribute can be used to add parameter descriptions
// The [OpenApiExample] attribute can be used to add simple string examples
// The ProducesOpenApiResponse() method can be used to customize the description for responses
app.MapGet("/todo", ([Description("The Todo item's ID"), OpenApiExample("42")] string id) =>
{
    return new Todo()
    {
        Id = id,
        Text = "Example",
        IsComplete = false,
    };
}).ProducesOpenApiResponse(StatusCodes.Status200OK, "The Todo item.");

app.MapPost("/todo", (Todo model) =>
{
    var todo = new Todo()
    {
        Id = Guid.NewGuid().ToString(),
        Text = model.Text,
        IsComplete = false,
    };
    return Results.Created($"/todo/{todo.Id}", todo);
}).ProducesOpenApiResponse(StatusCodes.Status201Created, "The created Todo item.");

app.Run();

// Classes can implement IExampleProvider<Todo> and decorate
// themselves with the [OpenApiExample<T>] attribute to use
// the example for all usage of the type in the OpenAPI document.
// Examples can also be added as attributes to parameters of operations,
// endpoint methods themselves, or as endpoint metadata.

[OpenApiExample<Todo>]
public class Todo : IExampleProvider<Todo>
{
    public string Id { get; set; }
    public string Text { get; set; }
    public bool IsComplete { get; set; }

    public static Todo GenerateExample() =>
        new()
        {
            Id = "42",
            Text = "Buy milk",
            IsComplete = false,
        };
}

// Custom IExampleProvider<T> implementations can be used to add more specific
// examples for types in the OpenAPI document, or for types that are not owned
// by the application itself (e.g. ASP.NET Core's ProblemDetails class).

public class ProblemDetailsExampleProvider : IExampleProvider<ProblemDetails>
{
    public static ProblemDetails GenerateExample()
    {
        return new()
        {
            Type = "https://tools.ietf.org/html/rfc7231#section-6.5.1",
            Title = "Bad Request",
            Status = StatusCodes.Status400BadRequest,
            Detail = "The specified value is invalid.",
        };
    }
}

// JSON source generation context to use to generate examples for JSON
// payloads that matches the runtime behaviour of the application itself
// (for example whether to use camelCase or PascalCase etc.)

[JsonSerializable(typeof(Todo))]
[JsonSerializable(typeof(ProblemDetails))]
[JsonSourceGenerationOptions(
    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
    PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
    WriteIndented = true)]
public partial class TodoJsonSerializerContext : JsonSerializerContext;

Building and Testing

Compiling the application yourself requires Git and the .NET SDK to be installed.

To build and test the application locally from a terminal/command-line, run the following set of commands:

git clone https://github.com/martincostello/openapi-extensions.git
cd openapi-extensions
./build.ps1

Feedback

Any feedback or issues can be added to the issues for this project in GitHub.

Repository

The repository is hosted in GitHub: https://github.com/martincostello/openapi-extensions.git

License

This project is licensed under the Apache 2.0 license.