Burgyn / MMLib.SwaggerForOcelot

This repo contains swagger extension for ocelot.
MIT License
352 stars 94 forks source link

Documentation of Ocelot Aggregates #134

Closed Burgyn closed 3 years ago

Burgyn commented 3 years ago

This PR brigns many times desired documentation of Request Aggregation. The first mention of this was more than a year ago (resolve #24, Thank you @JardoHornak for the inspiration).


Documentation of Ocelot Aggregates

services.AddSwaggerForOcelot(Configuration,
  (o) =>
  {
      o.GenerateDocsForAggregates = true;
  });

Documentations of you aggregates will be available on custom page Aggregates.

The current implementation may not cover all scenarios (I hope most of them), but there are several ways you can change the final documentation.

Custom description

By default, this package generate description from downstream documentation. If you want add custom description for your aggregate route, you can add description to ocelot.json.

"Aggregates": [ 
  {
    "RouteKeys": [
      "user",
      "basket"
    ],
    "Description": "Custom description for this aggregate route.",
    "Aggregator": "BasketAggregator",
    "UpstreamPathTemplate": "/gateway/api/basketwithuser/{id}"
  }
]

Different parameter names

It is likely that you will have different parameter names in the downstream services that you are aggregating. For example, in the User service you will have the {Id} parameter, but in the Basket service the same parameter will be called {BuyerId}. In order for Ocelot aggregations to work, you must have parameters named the same in Ocelot configurations, but this will make it impossible to find the correct documentation.

Therefore, you can help the configuration by setting parameter name map.

{
  "DownstreamPathTemplate": "/api/basket/{id}",
  "UpstreamPathTemplate": "/gateway/api/basket/{id}",
  "ParametersMap": {
    "id": "buyerId"
  },
  "ServiceName": "basket",
  "SwaggerKey": "basket",
  "Key": "basket"
}

Property ParametersMap is map, where key (first parameter) is the name of parameter in Ocelot configuration and value (second parameter) is the name of parameter in downstream service.

Custom aggregator

The response documentation is generated according to the rules that Ocelot uses to compose the response from the aggregate. If you use your custom IDefinedAggregator, your result may be different. In this case you can use AggregateResponseAttibute.

[AggregateResponse("Basket with buyer and busket items.", typeof(CustomResponse))]
public class BasketAggregator : IDefinedAggregator
{
    public async Task<DownstreamResponse> Aggregate(List<HttpContext> responses)
    {
        ...
    }
}

Modifying the generated documentation

If you do not like the final documentation, you can modify it by defining your custom postprocessor.

services.AddSwaggerForOcelot(Configuration,
  (o) =>
  {
      o.GenerateDocsForAggregates = true;
      o.AggregateDocsGeneratorPostProcess = (aggregateRoute, routesDocs, pathItemDoc, documentation) =>
      {
          if (aggregateRoute.UpstreamPathTemplate == "/gateway/api/basketwithuser/{id}")
          {
              pathItemDoc.Operations[OperationType.Get].Parameters.Add(new OpenApiParameter()
              {
                  Name = "customParameter",
                  Schema = new OpenApiSchema() { Type = "string"},
                  In = ParameterLocation.Header
              });
          }
      };
  });

If none of this is enough

🙏 Feel free to provide a PR with implementation of your scenario. You will probably help many others.

The Gateway documentation itself

If you need to, you can also add documentation.

  1. Allow GenerateDocsForGatewayItSelf option in configuration section.
services.AddSwaggerForOcelot(Configuration,
  (o) =>
  {
      o.GenerateDocsForGatewayItSelf = true;
  });
  1. Use Swagger generator in Configure section.
app.UseSwagger();