Is It Possible to Dynamically Add SwaggerEndpoints For SwaggerUI?

心已入冬 提交于 2019-12-23 12:25:36

问题


We're building out a services oriented architecture in .NET Core. We've decided to use Ocelot as our API gateway. I have integrated Ocelot with Consul for service discovery. Now I'm trying to attempt to create a unified Swagger UI for all the downstream services.

Prior to service discovery we had Swagger setup like this:

// Enable middleware to serve generated Swagger as a JSON endpoint
app.UseSwagger(c => { c.RouteTemplate = "{documentName}/swagger.json"; });

// Enable middleware to serve swagger-ui assets (HTML, JS, CSS etc.)
app.UseSwaggerUI(c =>
{
  c.SwaggerEndpoint("/docs/customer/swagger.json", "Customers Api Doc");
  c.SwaggerEndpoint("/docs/employee/swagger.json", "Employee Api Doc");
  c.SwaggerEndpoint("/docs/report/swagger.json", "Reports Api Doc");
});

On the Swagger UI this provides a "select a spec" dropdown. The developers like this functionality and we'd like to keep it. However, now that we've removed the manual configuration in favor of service discovery we would also like to have these endpoints dynamically updated.

With the current Swagger solution that's available is this possible? I haven't seen anything relating to service discovery or being able to dynamically configure the UI. Thoughts and suggestions?

Update

I've come up with a way to do this. It is a bit hack-ish and I'm hoping there is a way to do this that isn't so heavy handed.

public class Startup 
{
    static object LOCK = new object();

    SwaggerUIOptions options;

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<SwaggerUIOptions>((provider) =>
        {
            return this.options;
        });
        services.AddSingleton<IHostedService, SwaggerUIDocsAggregator>();
        services.AddSingleton<IConsulDiscoveryService, MyCounsulDiscoveryServiceImplementation>();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        // Enable middleware to serve generated Swagger as a JSON endpoint
        app.UseSwagger(c => { c.RouteTemplate = "{documentName}/swagger.json"; });
        // Enable middleware to serve swagger-ui assets (HTML, JS, CSS etc.)
        app.UseSwaggerUI(c =>
        {
            this.options = c;
        });
    }
}

public class SwaggerUIDocsAggregator : IHostedService
{
    static object LOCK = new object();

    IConsulDiscoveryService discoveryService;
    SwaggerUIOptions options;
    Timer timer;
    bool polling = false;
    int pollingInterval = 600;

    public ConsulHostedService(IConsulDiscoveryService discoveryService, SwaggerUIOptions options)
    {
        this.discoveryService = discoveryService;
        this.options = options;
    }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        this.timer = new Timer(async x =>
        {
            if (this.polling)
            {
                return;
            }

            lock (LOCK)
            {
                this.polling = true;
            }

            await this.UpdateDocs();

            lock (LOCK)
            {
                this.polling = false;
            }

        }, null, 0, pollingInterval);
    }

    public async Task StopAsync(CancellationToken cancellationToken)
    {
        this.timer.Dispose();
        this.timer = null;
    }

    private async Task UpdateDocs()
    {
        var discoveredServices = await this.discoveryService.LookupServices();

        var urls = new JArray();

        foreach (var kvp in discoveredServices)
        {
            var serviceName = kvp.Key;

            if (!urls.Any(u => (u as JObject).GetValue("url").Value<string>().Equals($"/{serviceName}/docs/swagger.json")))
            {

                urls.Add(JObject.FromObject(new { url = $"/{serviceName}/docs/swagger.json", name = serviceName }));
            }
        }

        this.options.ConfigObject["urls"] = urls;
    }
}

回答1:


Easy way for integration Ocelot api gateway as a unified Swagger UI for all the downstream services is project MMLib.SwaggerForOcelot.



来源:https://stackoverflow.com/questions/52784268/is-it-possible-to-dynamically-add-swaggerendpoints-for-swaggerui

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!