9

We have an API that contains some endpoints we want to expose publicly, and also some that we don't. However I don't simply want to exclude the private endpoints, I still want them to be visible, but only for certain users or at least under a different url. This seems like it should be fairly common but I am having trouble finding out how to do this.

Currently we have swagger set up and working, showing all endpoints. Some controllers are marked as a "public" group using the ApiExplorerSettings attribute like so (where SwaggerGroups.Public is a string constant "public"):

[ApiExplorerSettings(GroupName = SwaggerGroups.Public)]

Ideally we would have one swagger page that shows all controllers/methods marked public, and another, password secured endpoint that shows all endpoints. Is this possible?

QTom
  • 1,441
  • 1
  • 13
  • 29

1 Answers1

7

First, your problem sounds like you didn't properly separate your APIs and that in reality it should be two apis (two applications services in microservices terminology).

As such, you should treat it as two separate APIs too.

services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("public", new OpenApiInfo { Title = "My Public API", Version = "v1" });
    c.SwaggerDoc("private", new OpenApiInfo { Title = "My Private API", Version = "v1" });
});

This will generate two different OpenAPI (Swagger) specs. /api-docs/public/swagger.json and /api-docs/private/swagger.json, which can be hosted in two different UI applications (one protected other publically available)

// Public Docs Api
app.UseSwaggerUI(c =>
{
    // we use absolute uri here, since the swagger.json is outside of this application
    c.SwaggerEndpoint("http://example.com/api-docs/public/swagger.json", "Public API");
});


// Private Docs App
app.UseSwaggerUI(c =>
{
    c.SwaggerEndpoint("http://example.com/api-docs/private/swagger.json", "Private API");
});

An alternative approach is to use a build-pipeline/continuous integration system. Swashbuckle.AspNetCore provides an cli extensions in the 5.x version of the library, which can be executed as part of a build script to generate the swagger.json files during a build process.

For example

dotnet swagger tofile --output ../swagger/myapi/private.json MyCompany.MyApplication.Mvc private
dotnet swagger tofile --output ../swagger/myapi/public.json MyCompany.MyApplication.Mvc public

and have one docs App like this

// Private Docs App
app.UseSwaggerUI(c =>
{
    c.SwaggerEndpoint("http://example.com/api-docs/swagger/myapp/private.json", "Private API");
    c.SwaggerEndpoint("http://example.com/api-docs/swagger/myapp/public.json", "Public API");
});

where you protect "private.json" with Webserver means (nginx, apache, iis), i.e. allowing private.json access only in the internal network or only after authentication etc.

Alternative to the above, is to host both files in the same application, but secure the private file with a middleware, see this GitHub issue for some inspirations.

Tseng
  • 61,549
  • 15
  • 193
  • 205