Tuesday, March 28, 2023

Add OpenAPI (Swagger) support to ASP.Net Core Web API

OpenAPI (swagger) support gives many advantages to your web api. One of them is possibility to generate strongly typed clients for calling web api so instead of developing calls from scratch (with HttpClient, building requests, deserialize response, etc) we get ready for use client with POCO classes for requests and response data. In one of my previous articles I wrote how to generate such client for public web api with OpenAPI support: Generate C# client for API with Swagger (OpenAPI) support. In this article I will show how to add OpenAPI support to your own web api project.

We will use ASP.Net Core Web API project for code samples and the following simple controller:

[ApiController]
[Route("[controller]")]
public class UserController : ControllerBase
{
    public UserController()
    {
    }

    [HttpGet]
    [Route("List")]
    public IEnumerable<User> List()
    {
        throw new NotImplementedException();
    }

    [HttpGet]
    [Route("Details")]
    public User Details(int id)
    {
        throw new NotImplementedException();
    }

    [HttpPost]
    [Route("Save")]
    public void Save(User user)
    {
        throw new NotImplementedException();
    }

    [HttpDelete]
    [Route("Delete")]
    public void Delete(int id)
    {
        throw new NotImplementedException();
    }
}

public class User
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
}


First of all we need to add extra nuget package
Swashbuckle.AspNetCore
https://www.nuget.org/packages/Swashbuckle.AspNetCore

It is also possible to add OpenAPI support to web api project from beginning by checking "OpenAPI support" checkbox in create project dialog:

 

Now we need to add few extra lines to Program.cs for configuring Swagger endpoint (lines 7-10 and 15-19):

using Microsoft.OpenApi.Models;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "TestApi", Version = "v1" });
});

var app = builder.Build();

// Configure the HTTP request pipeline.
app.UseSwagger();
app.UseSwaggerUI(c =>
{
    c.SwaggerEndpoint("/swagger/v1/swagger.json", "TestApi v1");
});

app.UseAuthorization();

app.MapControllers();

app.Run();

Next we need to decorate actions of our controller with additional attributes which will describe which HTTP status codes may be returned from each endpoint, which data can be returned, etc.:

[ApiController]
[Route("[controller]")]
public class UserController : ControllerBase
{
    public UserController()
    {
    }

    [HttpGet]
    [Route("List")]
    [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(List<User>))]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    [ProducesDefaultResponseType]
    public IEnumerable<User> List()
    {
        throw new NotImplementedException();
    }

    [HttpGet]
    [Route("Details")]
    [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(User))]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    [ProducesDefaultResponseType]
    public User Details(int id)
    {
        throw new NotImplementedException();
    }

    [HttpPost]
    [Route("Save")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    [ProducesDefaultResponseType]
    public void Save(User user)
    {
        throw new NotImplementedException();
    }

    [HttpDelete]
    [Route("Delete")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status500InternalServerError)]
    [ProducesDefaultResponseType]
    public void Delete(int id)
    {
        throw new NotImplementedException();
    }
}

With these declarations Swagger sees that e.g. /details endpoint will return User object if everything went well (when HTTP status code is 200 Ok). Also it may return 404 Not found if user with specified id not found and 500 Internal server error if something went wrong in backend.

Now if we will run our web api and go to http://localhost:{port}/swagger/index.html we will see fancy automatically generated documentation for our api:

We may also expand endpoints and get more information about each of them:

Using these steps we've added OpenAPI support in our ASP.Net Core Web API project. In the next post I will show how to generate api client for this web api running on localhost (update 2023-03-29: see Generate strongly-typed C# client for ASP.Net Core Web API with OpenAPI (swagger) support running on localhost).

No comments:

Post a Comment