I've researched this issue and found a lot of articles and also q+as on here but nothing for my scenario. I have an asp.net core 3 API with 2 versions, 1 and 2. The API has 3 consumers, ConA, ConB, and ConC, and 3 controllers. ConA accesses controllers 1 and 2, ConB accesses only controller 3, and ConC accesses one endpoint from controller 1 and one endpoint from controller 3. For v1 I show everything but I now have a requirement to filter v2 endpoints by API consumer.
What I'm trying to do is create a Swagger document for each consumer that only shows the endpoints they can access. It's easy to do for ConA and ConB as I can use [ApiExplorerSettings(GroupName = "v-xyz")] where v-xyz can be restricted by consumer and then split the Swagger documents that way. The problem is showing the endpoints for ConC - they don't have their own controller so I can't give them a GroupName. Here's a simplified version of the code:
public void ConfigureServices(IServiceCollection services)
{
services.AddApiVersioning(options =>
{
options.ReportApiVersions = true;
options.AssumeDefaultVersionWhenUnspecified = true;
options.DefaultApiVersion = new ApiVersion(1, 0);
});
services.AddVersionedApiExplorer(options =>
{
options.GroupNameFormat = "'v'VV";
options.SubstituteApiVersionInUrl = true;
});
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo() { Title = "My API - Version 1", Version = "v1.0" });
c.SwaggerDoc("v2-conA", new OpenApiInfo() { Title = "My API - Version 2", Version = "v2.0" });
c.SwaggerDoc("v2-conB", new OpenApiInfo() { Title = "My API - Version 2", Version = "v2.0" });
c.SwaggerDoc("v2-conC", new OpenApiInfo() { Title = "My API - Version 2", Version = "v2.0" });
c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
c.EnableAnnotations();
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.EnableDeepLinking();
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
c.SwaggerEndpoint("/swagger/v2-conA/swagger.json", "My API V2 ConA");
c.SwaggerEndpoint("/swagger/v2-conB/swagger.json", "My API V2 ConB");
c.SwaggerEndpoint("/swagger/v2-conC/swagger.json", "My API V2 Con3");
});
}
Version 1 controllers:
[Route("api/account")]
[ApiController]
[ApiExplorerSettings(GroupName = "v1")]
public class AccountController : ControllerBase
{
[HttpGet("get-user-details")]
public ActionResult GetUserDetails([FromQuery]string userId)
{
return Ok(new { UserId = userId, Name = "John", Surname = "Smith", Version = "V1" });
}
}
[Route("api/account-admin")]
[ApiController]
[ApiExplorerSettings(GroupName = "v1")]
public class AccountAdminController : ControllerBase
{
[HttpPost("verify")]
public ActionResult Verify([FromBody]string userId)
{
return Ok($"{userId} V1");
}
}
[Route("api/notification")]
[ApiController]
[ApiExplorerSettings(GroupName = "v1")]
public class NotificationController : ControllerBase
{
[HttpPost("send-notification")]
public ActionResult SendNotification([FromBody]string userId)
{
return Ok($"{userId} V1");
}
}
Version 2 controllers (namespaced in separate folder "controllers/v2"):
[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/account")]
[ApiController]
[ApiExplorerSettings(GroupName = "v2-conA")]
public class AccountController : ControllerBase
{
[HttpGet("get-user-details")]
[SwaggerOperation(Tags = new[] { "ConA - Account" })]
public ActionResult GetUserDetails([FromQuery]string userId)
{
return Ok($"{userId} V2");
}
}
[Route("api/v{version:apiVersion}/account-admin")]
[ApiController]
[ApiVersion("2.0")]
[ApiExplorerSettings(GroupName = "v2-conB")]
public class AccountAdminController : ControllerBase
{
[HttpPost("verify")]
[SwaggerOperation(Tags = new[] { "ConB - Account Admin", "ConC - Account Admin" })]
public ActionResult Verify([FromBody] string userId)
{
return Ok($"{userId} V2");
}
}
[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/notification")]
[ApiController]
[ApiExplorerSettings(GroupName = "v2-conA")]
public class NotificationController : ControllerBase
{
[HttpPost("send-notification")]
[SwaggerOperation(Tags = new[] { "ConA - Notification", "ConC - Notification" })]
public ActionResult SendNotification([FromBody] string userId)
{
return Ok($"{userId} V2");
}
}
This gets me some of the way in that I can see the endpoints for ConA and ConB, although it's not perfect as it's showing duplicate endpoints, but I'm stuck on how to show the endpoints for ConC (who can see one endpoint from controller 1 and one from controller 3). My next attempt will be to go back to showing all endpoints in version 2 and then filtering using IDocumentFilter if I can't get the above working somehow. Any thoughts or tips greatly appreciated




