Swashbuckle.aspnetcore: Serving a master swagger document based on several small swagger documents

Created on 30 Sep 2016  路  5Comments  路  Source: domaindrivendev/Swashbuckle.AspNetCore

Hi,

I'm currently working on a micro services architecture, with multiple small web api applications. More or less one micro service per main resource. The micro services are hosted within Azure Service Fabric.

However I don't want to expose my internal architecture to my consumers from the big bad outside world. So I expose those micro services via an api gateway.

I use Swashbuckle to generate the swagger documents, for each web api exposed by the micro services. I think this is the right responsibility at the right place. However, it would be nice if I could host a combined swagger document in the api gateway. Would that be something that is a nice addition to Swashbuckle?

Most helpful comment

Hello @domaindrivendev , can I find some example of implementation of ISwaggerProvider with combines Json documents? Or any suggestion. Thanks

All 5 comments

Thinking about this a bit more in detail, I think the easiest approach would be just some json merge for the following properties into a new swagger specification.

  • paths
  • definitions
  • parameters
  • responses
  • securityDefinitions
  • security
  • tags
  • externalDocs

I don't think implementations like this should be part of swashbuckle, sounds like it would be polution to the existing functionality. What do you think?

Swashbuckle currently comprises 3 separate components that can be used together or independently depending on your needs:

  • Swashbuckle.Swagger exposes a C# SwaggerDocument as a JSON API. It expects an implementation of ISwaggerProvider to be registered and then queries that to get the swagger document by name
  • Swashbuckle.SwaggerGen injects an implementation of ISwaggerProvider that can be used by the above component. This particular implementation generates SwaggerDocument(s) directly from your routes and controllers.
  • Swashbuckle.SwaggerUi exposes the swagger-ui, single page application. You specify the API endpoints where it can obtain Swagger JSON and it uses these to power the slick discovery UI.

For your Microservices infrastructure you could use a combination of these and a custom ISwaggerProvider to implement what you need.

Each Microservice would install Swashbuckle.Swagger and Swashbuckle.SwaggerGen to generate and expose Swagger JSON.

Then, in a dedicated "documentation" application, you could install Swashbuckle.Swagger and Swashbuckle.SwaggerUi. Here, you'll need to register an implementation of ISwaggerProvider with the IoC container for this to work. This would be your own custom implementation which makes remote calls to obtain the Swagger JSON from each Microservice and then combines them (i.e. JSON merge) to produce an uber Swagger document. If you configure everything correctly, the custom implementation of ISwaggerProvider should be the only significant lines of code you'd have to write

Hello @domaindrivendev , can I find some example of implementation of ISwaggerProvider with combines Json documents? Or any suggestion. Thanks

@Marusyk, were you able to achieve this? We are also developing our APIs as microservices, and each API is in a separate project. I am able to export my specs during build (using NSwag) however I'm now tasked with being able to combine my specs into a master file to serve with ReDoc. I only want to pull operations from one spec file into another master spec file.

Hi @EspressoBeans,

Yeah, we are using Swashbuckle with Ocelot API gateway.

Each microservice has installed only Swashbuckle.AspNetCore.SwaggerGen to generate and expose Swagger JSON.

The API gateway knows about other services, so we need to just grab their swagger jsons.
API gateway project has installed only the Swashbuckle.AspNetCore.SwaggerUI package.

At the end we can find out swagger of user service by http://gateway.com/users/swagger

Here are some code:

It each microservice:

services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new Info { Title = "User service", Version = "v1" });
    c.CustomSchemaIds(schema => schema.FullName);
});

and

app.UseSwagger(options =>
{
      options.PreSerializeFilters.Add((swaggerDoc, httpReq) => swaggerDoc.BasePath = "/users");
      options.RouteTemplate = "/{documentName}/swagger.json";
});

in API gateway

app.UseSwaggerUI(setup =>
{
    setup.RoutePrefix = "docs";
    foreach (var service in configuration.Get<FileConfiguration>().ReRoutes) <-- here we get all route to internal services
    {
        var address = service.DownstreamHostAndPorts.First(); <-- like: https://localhost:3322
        var url = $"{service.DownstreamScheme}://{address.Host}:{address.Port}/v1/swagger.json";  <-- get actual url to service swagger json
        var jsonEndpoint = $"/{service.Key}/v1/swagger.json";  <-- service.Key is name of sevice from route, so we got url to json of service through gateway

        app.Map(jsonEndpoint, b =>   <-- create endpoint to each service like: http://gateway.com/users/v1/swagger.json
        {
            b.Run(async x =>
            {
                string content = await _httpClient.GetStringAsync(url); <-- read json of service by url https://localhost:3322/v1/swagger.json
                await x.Response.WriteAsync(content);
            });
        });

        setup.SwaggerEndpoint(jsonEndpoint, service.Key);
    }
});

Also I've attached the example of file with gateway configuration.

ocelot.zip

Hope this will help. Let me know if you need more details.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

NinoFloris picture NinoFloris  路  3Comments

flipchart picture flipchart  路  4Comments

TimmyGilissen picture TimmyGilissen  路  3Comments

nezoic picture nezoic  路  3Comments

vanillajonathan picture vanillajonathan  路  3Comments