derodevil
derodevil

Reputation: 1073

How to group controller using OpenAPI and Scalar API documentations

I have an ASP.NET Core 9 Web API application. By default, .NET9 doesn't use Swashbuckle anymore. To generate API documentations I'm using Microsoft OpenAPI documents and Scalar.

It works fine. I need to group all endpoints into smaller groups. For example, User, Order etc. User group will contain authentication controller, changing profile profile controller and Order group will contain order controller and payment controller.

Is it possible to group those endpoints?

Upvotes: 3

Views: 926

Answers (3)

Feech
Feech

Reputation: 504

Use the Tags attribute. I've found Scalar will group the methods under those tags perfectly. Something similar to:

[EndpointDescription("Retrieve a paged list of people based on a set of filters")]
[EndpointSummary("List People")]
[Tags("People")]
[HttpGet("people")]
[ProducesResponseType<PagedResultDto<PersonDto>>(StatusCodes.Status200OK, "application/json")]
public async Task<IActionResult> GetPeople([FromQuery] GetPeopleInputDto inputDto)
{ ... }

enter image description here

Upvotes: 3

Zhi Lv
Zhi Lv

Reputation: 21636

What I'm looking for is grouping multiple controllers into a single group name.

You can try to use [ApiExplorerSettings] attribute and a Swagger operation filter or API conventions to group multiple API controllers under a single group name.

Add [ApiExplorerSettings] attribute in the controller, code like this:

[Route("api/[controller]")]
[ApiController]
[ApiExplorerSettings(GroupName = "MyGroup")]
public class TodoController : ControllerBase
{

and

[Route("api/[controller]")]
[ApiController]
[ApiExplorerSettings(GroupName = "MyGroup")]
public class ValuesController : ControllerBase
{

then, in the Program.cs file:

builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });

    c.DocInclusionPredicate((docName, apiDesc) =>
    {
        if (docName == "MyGroup")
        {
            return apiDesc.GroupName == "MyGroup";
        }
        return true;
    }); 
    c.TagActionsBy(api => new[] { api.GroupName ?? "Default" });
});

The result as below:

swagger result

Using Scalar to check the https://localhost:7045/swagger/v1/swagger.json, the result like this:

enter image description here

Upvotes: 0

Zhi Lv
Zhi Lv

Reputation: 21636

You can use Swashbuckle.AspNetCore and Scalar.AspNetCore together to group the controllers and endpoints.

You can check the following sample:

NET9API.csproj: Installed the Swashbuckle.AspNetCore and Scalar.AspNetCore package from NuGet.

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
    <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="9.0.0" />
    <PackageReference Include="Scalar.AspNetCore" Version="1.2.44" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.9.0" />
  </ItemGroup>

</Project>

Then, in the Program.cs file:

using Scalar.AspNetCore;
using NET9API.Controllers;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
builder.Services.AddOpenApi();

builder.Services.AddEndpointsApiExplorer();

builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
    app.MapScalarApiReference();
}

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

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.MapUserEndpoints(); //after adding the "API endpoints via API with Read/write endpoints" Scaffold, we can add the maps.
  
app.Run();

Then, we can use the following options to add controller or endpoints:

add controller

In this example, I've added the Values controller and the Users endpoint in the same way as above.

The ValuesController.cs file like this:

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    // GET: api/<ValuesController>
    [HttpGet]
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }

    // GET api/<ValuesController>/5
    [HttpGet("{id}")]
    public string Get(int id)
    {
        return "value";
    }

    // POST api/<ValuesController>
    [HttpPost]
    public void Post([FromBody] string value)
    {
    }

    // PUT api/<ValuesController>/5
    [HttpPut("{id}")]
    public void Put(int id, [FromBody] string value)
    {
    }

    // DELETE api/<ValuesController>/5
    [HttpDelete("{id}")]
    public void Delete(int id)
    {
    }
}

and the UsersController.cs file as below:

using NET9API.Models;
namespace NET9API.Controllers;

public static class UsersController
{
    public static void MapUserEndpoints (this IEndpointRouteBuilder routes)
    {
        var group = routes.MapGroup("/api/User").WithTags(nameof(User));

        group.MapGet("/", () =>
        {
            return new [] { new User() };
        })
        .WithName("GetAllUsers")
        .WithOpenApi();

        group.MapGet("/{id}", (int id) =>
        {
            //return new User { ID = id };
        })
        .WithName("GetUserById")
        .WithOpenApi();

        group.MapPut("/{id}", (int id, User input) =>
        {
            return TypedResults.NoContent();
        })
        .WithName("UpdateUser")
        .WithOpenApi();

        group.MapPost("/", (User model) =>
        {
            //return TypedResults.Created($"/api/Users/{model.ID}", model);
        })
        .WithName("CreateUser")
        .WithOpenApi();

        group.MapDelete("/{id}", (int id) =>
        {
            //return TypedResults.Ok(new User { ID = id });
        })
        .WithName("DeleteUser")
        .WithOpenApi();
    }
}

After running the application, and use Scalar to check the openAPI json file (https://localhost:{port}/openapi/v1.json), the output as below:

test result

Upvotes: 0

Related Questions