Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IsItSelfGatewayFirstDefinition implementation #305

Open
EynsherKiel opened this issue Aug 21, 2024 · 1 comment
Open

IsItSelfGatewayFirstDefinition implementation #305

EynsherKiel opened this issue Aug 21, 2024 · 1 comment

Comments

@EynsherKiel
Copy link

EynsherKiel commented Aug 21, 2024

Hello there,

I suggest adding the [it self gateway first definition] property to ensure that Gateway is the first definition in the list. Full code implementation in the comments, thanks!

using Microsoft.OpenApi.Models;
using MMLib.SwaggerForOcelot.Aggregates;
using System;
using System.Collections.Generic;

namespace MMLib.SwaggerForOcelot.Configuration
{
    /// <summary>
    /// Options for generating docs of ApiGateway.
    /// </summary>
    public class OcelotSwaggerGenOptions
    {
        /// <summary>
        /// Gets or sets a value indicating whether [generate docs for aggregates].
        /// </summary>
        /// <value>
        ///   <c>true</c> if [generate docs for aggregates]; otherwise, <c>false</c>.
        /// </value>
        public bool GenerateDocsForAggregates { get; set; } = false;

        /// <summary>
        /// Gets or sets a value indicating whether [generate docs for gateway it self].
        /// </summary>
        /// <value>
        ///   <c>true</c> if [generate docs for gateway it self]; otherwise, <c>false</c>.
        /// </value>
        public bool GenerateDocsForGatewayItSelf { get; set; } = false;

        /// <summary>
        /// Gets or sets a value indicating whether [it self gateway first definition].
        /// </summary>
        /// <value>
        ///   <c>true</c> if [it self gateway first definition]; otherwise, <c>false</c>.
        /// </value>
        public bool IsItSelfGatewayFirstDefinition { get; set; } = false;

        /// <summary>
        /// Gets or sets a value indicating downstream docs cache expire duration in seconds.
        /// </summary>
        /// <value>
        ///     <c>0</c> if it won't be cached; otherwise, cache expire duration in seconds.
        /// </value>
        public TimeSpan DownstreamDocsCacheExpire { get; set; } = TimeSpan.Zero;

        /// <summary>
        /// Generates docs for gateway it self with options.
        /// </summary>
        /// <param name="options">Gateway itself docs generation options.</param>
        public void GenerateDocsDocsForGatewayItSelf(Action<OcelotGatewayItSelfSwaggerGenOptions> options = null)
        {
            GenerateDocsForGatewayItSelf = true;

            OcelotGatewayItSelfSwaggerGenOptions = new OcelotGatewayItSelfSwaggerGenOptions();
            options?.Invoke(OcelotGatewayItSelfSwaggerGenOptions);

            GatewayDocsTitle = OcelotGatewayItSelfSwaggerGenOptions.GatewayDocsTitle ?? GatewayDocsTitle;
            GatewayDocsOpenApiInfo = OcelotGatewayItSelfSwaggerGenOptions.GatewayDocsOpenApiInfo ?? GatewayDocsOpenApiInfo;
        }

        /// <summary>
        /// Adds a mapping between Ocelot's AuthenticationProviderKey and Swagger's securityScheme
        /// If a route has a match, security definition will be added to the endpoint with the provided AllowedScopes from the config.
        /// </summary>
        /// <param name="authenticationProviderKey"></param>
        /// <param name="securityScheme"></param>
        public void AddAuthenticationProviderKeyMapping(string authenticationProviderKey, string securityScheme)
        {
            AuthenticationProviderKeyMap.Add(authenticationProviderKey, securityScheme);
        }

        /// <summary>
        /// Register aggregate docs generator post process.
        /// </summary>
        public Action<SwaggerAggregateRoute, IEnumerable<RouteDocs>, OpenApiPathItem, OpenApiDocument> AggregateDocsGeneratorPostProcess { get; set; }
             = AggregateRouteDocumentationGenerator.DefaultPostProcess;

        internal static OcelotSwaggerGenOptions Default { get; } = new OcelotSwaggerGenOptions();

        internal const string AggregatesKey = "aggregates";

        internal const string GatewayKey = "gateway";

        internal string GatewayDocsTitle { get; set; } = "Gateway";

        internal OpenApiInfo GatewayDocsOpenApiInfo { get; set; } = new()
        {
            Title = "Gateway",
            Version = GatewayKey,
        };

        internal OcelotGatewayItSelfSwaggerGenOptions OcelotGatewayItSelfSwaggerGenOptions { get; private set; }

        internal Dictionary<string, string> AuthenticationProviderKeyMap { get; } = new();
    }
}
using Kros.Utils;
using Microsoft.Extensions.Options;
using MMLib.SwaggerForOcelot.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;

namespace MMLib.SwaggerForOcelot.Repositories
{
    /// <summary>
    /// Provider for obtaining <see cref="SwaggerEndPointOptions"/>.
    /// </summary>
    public class SwaggerEndPointProvider : ISwaggerEndPointProvider
    {
        private readonly Lazy<Dictionary<string, SwaggerEndPointOptions>> _swaggerEndPoints;
        private readonly IOptionsMonitor<List<SwaggerEndPointOptions>> _swaggerEndPointsOptions;
        private readonly OcelotSwaggerGenOptions _options;

        /// <summary>
        /// Initializes a new instance of the <see cref="SwaggerEndPointProvider"/> class.
        /// </summary>
        /// <param name="swaggerEndPoints">The swagger end points.</param>
        public SwaggerEndPointProvider(
            IOptionsMonitor<List<SwaggerEndPointOptions>> swaggerEndPoints,
            OcelotSwaggerGenOptions options)
        {
            _swaggerEndPointsOptions = Check.NotNull(swaggerEndPoints, nameof(swaggerEndPoints));

            _swaggerEndPoints = new Lazy<Dictionary<string, SwaggerEndPointOptions>>(Init);
            _options = options;
        }

        /// <inheritdoc/>
        public IReadOnlyList<SwaggerEndPointOptions> GetAll()
            => _swaggerEndPoints.Value.Values.ToList();

        /// <inheritdoc/>
        public SwaggerEndPointOptions GetByKey(string key)
            => _swaggerEndPoints.Value[$"/{key}"];

        private Dictionary<string, SwaggerEndPointOptions> Init()
        {
            var ret = _swaggerEndPointsOptions.CurrentValue.Select(p => KeyValuePair.Create($"/{p.KeyToPath}", p));

            if (_options.GenerateDocsForAggregates)
            {
                ret = ret.Append(AddEndpoint(OcelotSwaggerGenOptions.AggregatesKey, "Aggregates"));
            }

            if (_options.GenerateDocsForGatewayItSelf)
            {
                var gateway = AddEndpoint(OcelotSwaggerGenOptions.GatewayKey, _options.GatewayDocsTitle);

                ret = _options.IsItSelfGatewayFirstDefinition ?
                    ret.Prepend(gateway) :
                    ret.Append(gateway);
            }

            return ret.ToDictionary(x => x.Key, x => x.Value);
        }

        private static KeyValuePair<string, SwaggerEndPointOptions> AddEndpoint(string key, string description)
            => KeyValuePair.Create($"/{key}", new SwaggerEndPointOptions()
            {
                Key = key,
                TransformByOcelotConfig = false,
                Config = new List<SwaggerEndPointConfig>() {
                    new SwaggerEndPointConfig()
                    {
                        Name = description,
                        Version = key,
                        Url = ""
                    }
                }
            });
    }
}
@EynsherKiel
Copy link
Author

EynsherKiel commented Aug 21, 2024

btw, my workaround

public class SwaggerEndPointProviderFixedFilter(
    IOptionsMonitor<List<SwaggerEndPointOptions>> swaggerEndPoints,
    OcelotSwaggerGenOptions options) : SwaggerEndPointProvider(
        swaggerEndPoints: swaggerEndPoints,
        options: options), ISwaggerEndPointProvider
{
    public new IReadOnlyList<SwaggerEndPointOptions> GetAll() => [.. base.GetAll().OrderByDescending(x => x.Key == "gateway")];
}
services.AddTransient<ISwaggerEndPointProvider, SwaggerEndPointProviderFixedFilter>();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant