KaraKaplan
KaraKaplan

Reputation: 798

Grouping Swagger by Project in .Net Core

I am working on a project which I named as "main-project". I have at least 10 different small project in there and this project will probably grow. I have just one swagger for all these projects because all these projects use just one dotnet core web application for generalization purpose.

For example, let's say I have project named SchoolJob and project named HospitalJob. SchoolJob has three different endpoints named GetStudents, TakeStudents, GetPayment and HostpitalJob has two endpoint named GetDoctors and GetNurses. These two different project will be seen in one swagger UI like that:

 - ../schooljob/getstudents
 - ../schooljob/takestudents 
 - ../schooljob/getpayment
 - ../hospitaljob/getdoctors
 - ../hospitaljob/getnurses

What I want to do is setting multiple different swagger page in one dotnet core web project or grouping one swagger so that they will be seen on different page / or on the same page but not the same time.

../mainproject/swagger1/index.html or mainproject/swagger/schooljob UI should be like that:

 - ../schooljob/getstudents
 - ../schooljob/takestudents 
 - ../schooljob/getpayment

../mainproject/swagger2/index.html or mainproject/swagger/hospitaljob UI should be like that

 - ../hospitaljob/getdoctors
 - ../hospitaljob/getnurses
// Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    c.SwaggerDoc("schooljob", new OpenApiInfo
    {
        Version = "schooljob",
        Title = "School Job"
    });
    c.SwaggerDoc("hospitaljob", new OpenApiInfo
    {
        Version = "hospitaljob",
        Title = "Hospital Job"
    });
    // c.AddSecurityDefinition... and other swagger configurations
}   
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider)
{
    app.UseSwagger(c =>
    {
        c.RouteTemplate = "mainproject/swagger/{documentname}/swagger.json";
    });
    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/mainproject/swagger/schooljob/swagger.json", "School Job");
        c.SwaggerEndpoint("/mainproject/swagger/hospitaljob/swagger.json", "Hospital Job");
        c.RoutePrefix = "mainproject/swagger";
        /c second prefix how?
    });
}
// SchoolController.cs

[HttpPost("schooljob/getstudents")]
[ApiExplorerSettings(GroupName = "schooljob")]
public JsonResult GetStudents([FromBody]OnaySayfasiId onaySayfasi)
{ ... }
// HospitalController.cs

[HttpPost("hospitaljob/getdoctors")]
[ApiExplorerSettings(GroupName = "hospitaljob")]
public JsonResult GetDoctors([FromBody]OnaySayfasiId onaySayfasi)
{ ... }

By the way, I tried using grouping by Api Version but I saw all these endpoints again. Is there any method for doing this?

Upvotes: 1

Views: 3211

Answers (2)

Shareef DotNet Guru
Shareef DotNet Guru

Reputation: 51

use the below code in program.cs (.net 6), If you are using .net 5(or below version) use this code in strartup.cs

services.AddVersionedApiExplorer(options =>
    {
        options.GroupNameFormat = "'v'VV";
        options.SubstituteApiVersionInUrl = true;
    });


services.AddSwaggerGen(options =>
        {

            options.DocInclusionPredicate((documentName, apiDescription) =>
            {
                var actionApiVersionModel = apiDescription.ActionDescriptor.GetApiVersionModel();
                var apiExplorerSettingsAttribute = (ApiExplorerSettingsAttribute)apiDescription.ActionDescriptor.EndpointMetadata.First(x => x.GetType().Equals(typeof(ApiExplorerSettingsAttribute)));
                if (actionApiVersionModel == null)
                {
                    return true;
                }
                if (actionApiVersionModel.DeclaredApiVersions.Any())
                {
                    return actionApiVersionModel.DeclaredApiVersions.Any(v =>
                    $"{apiExplorerSettingsAttribute.GroupName}v{v}" == documentName);
                }
                return actionApiVersionModel.ImplementedApiVersions.Any(v =>
                       $"{apiExplorerSettingsAttribute.GroupName}v{v}" == documentName);
            });

            var apiVersionDescriptionProvider = services.BuildServiceProvider().GetService<IApiVersionDescriptionProvider>();
            foreach (var description in apiVersionDescriptionProvider.ApiVersionDescriptions)
            {
                options.SwaggerDoc($"Orders{description.GroupName}", new OpenApiInfo
                {
                    Title = "Example Service",
                    Description = "Example Service -- Backend Service Project",
                    Version = description.ApiVersion.ToString(),
                    
                });
                options.SwaggerDoc($"Payments{description.GroupName}", new OpenApiInfo
                {
                    Title = "Example Service",
                    Description = "Example Service -- Backend Service Project",
                    Version = description.ApiVersion.ToString(),
                });
                // Orders & Payments are the groupName above ex: out put will be : swagger/OrdersV1.0/swagger.json ( if you select Orders from the swagger definition dropdown) 
                // If you select Payments => output : swagger/PaymentsV1.0/swagger.json
            }
            
            
var app = builder.Build();
                
            app.UseSwagger();

            app.UseSwaggerUI(
            swaggerOptions =>
            {                   
                foreach (var description in provider.ApiVersionDescriptions)
                {
                    swaggerOptions.SwaggerEndpoint($"{swagger/Orders{description.GroupName}/swagger.json",$"Orders  {description.GroupName.ToUpperInvariant()}" );
                    swaggerOptions.SwaggerEndpoint($"{swagger/Payments{description.GroupName}/swagger.json", $"Payments  {description.GroupName.ToUpperInvariant()}");
                }
            }); 
            
            
            

Controller //V1 // example controller 1:

[ApiVersion("1.0")]
[ApiController]
[ApiExplorerSettings(GroupName = "Orders")]
[Route("api/v{version:apiVersion}/[controller]")]
public class OrdersController : ControllerBase              
            

// example controller 2:

[ApiVersion("1.0")]
[ApiController]
[ApiExplorerSettings(GroupName = "Payments")]
[Route("api/v{version:apiVersion}/[controller]")]
public class PaymentsController : ControllerBase    

Upvotes: 1

Bruno Martins
Bruno Martins

Reputation: 962

I see what you're missing, you used the wrong controller attribute, here what you can do:

  • In the controllers, you have to use [ApiVersion] instead of the [ApiExplorerSettings(GroupName = ...)] attribute. Groups are different, I guess they are about grouping endpoints under the same section in the Swagger page.
  • When a method argument requires a version, be consistent. OpenApiInfo, SwaggerEndpoint, ApiVersion need the same string, for example schooljob and not School Job.

I guess it should work if you update your code as below:

// Startup.cs

app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/mainproject/swagger/schooljob/swagger.json", "schooljob");
        c.SwaggerEndpoint("/mainproject/swagger/hospitaljob/swagger.json", "hospitaljob");
        c.RoutePrefix = "mainproject/swagger";
        // No need for 2nd route prefix as there is only one Swagger page,
        // the content of the page gets updated when selecting a different version in the combobox.
    });

/* This line may be required in ConfigureServices method, give it a try */
/* services.AddApiVersioning(); */
// SchoolController.cs

[HttpPost("schooljob/getstudents")]
[ApiVersion("schooljob")]
public JsonResult GetStudents([FromBody]OnaySayfasiId onaySayfasi)
{ ... }

I hope it solves your problem!

Upvotes: 2

Related Questions