How to use OpenAPI in ASP.NET Core

By FoxLearn 12/31/2024 6:27:02 AM   113
In ASP.NET Core, you can easily document your HTTP endpoints using OpenAPI support, which includes Swagger UI for a graphical interface.

This is especially useful when working with minimal APIs introduced in ASP.NET Core 6, which simplifies the creation of lightweight APIs by reducing boilerplate code.

What is OpenAPI?

The OpenAPI specification, formerly known as Swagger, is a standardized, machine-readable language-independent format for describing HTTP APIs. It serves as an interface description language (IDL) that is agnostic to programming languages.

  • Defining endpoint information.
  • Formatting this data in a way that adheres to OpenAPI standards.
  • Exposing the OpenAPI schema through either a graphical interface (like Swagger UI) or a serialized file.

In ASP.NET Core 7, the Swashbuckle.AspNetCore package is included by default in Web API projects, providing tools for automatic Swagger documentation.

Creating a Minimal API with OpenAPI Documentation

To create a simple minimal API endpoint in ASP.NET Core, the default setup generates an HTTP GET endpoint in the Program.cs file.

app.MapGet("/", () => "Hello World!")
   .WithName("Welcome")
   .WithOpenApi();

When the app runs, Swagger UI will display this endpoint. You can configure Swagger using the following code:

builder.Services.AddSwaggerGen(setup => setup.SwaggerDoc("v1", new OpenApiInfo()
{
    Description = "Minimal API Demo",
    Title = "API Example",
    Version = "v1",
    Contact = new OpenApiContact()
    {
        Name = "Developer Name",
        Url = new Uri("https://developerwebsite.com")
    }
}));

This metadata will appear in the Swagger UI, providing more details about the API.

Adding a Model and Repository

To extend the minimal API example, let's create a model and an interface for managing data. Here's an example of a Book model and a corresponding repository interface:

public class Book
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Author { get; set; }
    public string ISBN { get; set; }
}

Next, define the repository interface:

public interface IBookRepository
{
    Book GetById(int id);
    void Create(Book book);
    void Update(Book book);
    void Delete(Book book);
}

A skeleton BookRepository class can implement this interface:

public class BookRepository : IBookRepository
{
    public void Create(Book book) { throw new NotImplementedException(); }
    public void Delete(Book book) { throw new NotImplementedException(); }
    public Book GetById(int id) { throw new NotImplementedException(); }
    public void Update(Book book) { throw new NotImplementedException(); }
}

Creating Endpoints

Now, define the minimal API endpoints for managing books in Program.cs. The following endpoints represent common CRUD operations:

app.MapGet("/books/{id}", async ([FromServices] IBookRepository repo, int id) =>
{
    var book = repo.GetById(id);
    return book != null ? Results.Ok(book) : Results.NotFound();
});

app.MapPost("/books", async ([FromServices] IBookRepository repo, Book book) =>
{
    repo.Create(book);
    return Results.Created($"/books/{book.Id}", book);
});

app.MapPut("/books/{id}", async ([FromServices] IBookRepository repo, int id, Book bookToUpdate) =>
{
    var existingBook = repo.GetById(id);
    if (existingBook == null)
        return Results.NotFound();
    
    repo.Update(bookToUpdate);
    return Results.Ok(bookToUpdate);
});

app.MapDelete("/books/{id}", async ([FromServices] IBookRepository repo, int id) =>
{
    var book = repo.GetById(id);
    if (book == null)
        return Results.NotFound();

    repo.Delete(book);
    return Results.NoContent();
});

These endpoints will be displayed in the Swagger UI, allowing developers to interact with the API directly through the browser.

Complete Example Code

Here is the complete code for a minimal API with OpenAPI documentation:

using Microsoft.AspNetCore.Mvc;
using Microsoft.OpenApi.Models;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSwaggerGen(setup => setup.SwaggerDoc("v1", new OpenApiInfo()
{
    Description = "Minimal API Demo",
    Title = "API Example",
    Version = "v1",
    Contact = new OpenApiContact()
    {
        Name = "Developer Name",
        Url = new Uri("https://developerwebsite.com")
    }
}));

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.MapGet("/books/{id}", async ([FromServices] IBookRepository repo, int id) =>
{
    var book = repo.GetById(id);
    return book != null ? Results.Ok(book) : Results.NotFound();
});
app.MapPost("/books", async ([FromServices] IBookRepository repo, Book book) =>
{
    repo.Create(book);
    return Results.Created($"/books/{book.Id}", book);
});
app.MapPut("/books/{id}", async ([FromServices] IBookRepository repo, int id, Book bookToUpdate) =>
{
    var existingBook = repo.GetById(id);
    if (existingBook == null)
        return Results.NotFound();
    
    repo.Update(bookToUpdate);
    return Results.Ok(bookToUpdate);
});
app.MapDelete("/books/{id}", async ([FromServices] IBookRepository repo, int id) =>
{
    var book = repo.GetById(id);
    if (book == null)
        return Results.NotFound();

    repo.Delete(book);
    return Results.NoContent();
});

app.Run();

public class Book
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Author { get; set; }
    public string ISBN { get; set; }
}

public interface IBookRepository
{
    Book GetById(int id);
    void Create(Book book);
    void Update(Book book);
    void Delete(Book book);
}

public class BookRepository : IBookRepository
{
    public void Create(Book book) { throw new NotImplementedException(); }
    public void Delete(Book book) { throw new NotImplementedException(); }
    public Book GetById(int id) { throw new NotImplementedException(); }
    public void Update(Book book) { throw new NotImplementedException(); }
}

ASP.NET Core provides a powerful, built-in OpenAPI integration for documenting minimal APIs. By enabling OpenAPI support when creating a project, you can automatically generate API documentation and explore it via Swagger UI.