Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hide/show controllers in SwaggerUI (configurable)

We would like SwaggerUI, which is being generated by Swashbuckle, to show all controllers and methods when debugging as well as on our test environment, but hide some on integration and production environments. Note that the hidden controllers/methods will be functional in all scenarios but won't be documented in SwaggerUI.

To do this I've applied the principal described here.

Which results in following code:

Attribute definition:

using System;
using Microsoft.AspNetCore.Mvc;

namespace Test
{
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
    public class SwaggerUIVisibilityAttribute : ApiExplorerSettingsAttribute
    {
        public SwaggerUIVisibilityAttribute(SwaggerUIVisibility visibility)
        {
            Visibility = visibility;
        }

        public SwaggerUIVisibility Visibility { get; }
    }

    public enum SwaggerUIVisibility
    {
        Debug,
        Internal,
        Public
    }
}

Filter (work in progress):

using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Reflection;
using Microsoft.AspNetCore.Mvc.ApiExplorer;

namespace Test
{
    public class SwaggerUIVisibilityFilter : IDocumentFilter
    {
        #region Private Fields

        private readonly SwaggerUIVisibility _swaggerUIVisibility;

        #endregion

        #region Constructors

        public SwaggerUIVisibilityFilter(SwaggerUIVisibility swaggerUIVisibility)
        {
            _swaggerUIVisibility = swaggerUIVisibility;
        }

        #endregion

        #region Public Methods

        public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
        {
            foreach (var apiDescription in context.ApiDescriptions)
            {
                var controllerActionDescriptor = apiDescription.ActionDescriptor as ControllerActionDescriptor;

                var controllerSwaggerUIVisibilityAttribute = controllerActionDescriptor?.ControllerTypeInfo
                                                                                       .GetCustomAttributes<SwaggerUIVisibilityAttribute>()
                                                                                       .SingleOrDefault();

                var methodSwaggerUIVisibilityAttribute = controllerActionDescriptor?.MethodInfo
                                                                                   .GetCustomAttributes<SwaggerUIVisibilityAttribute>()
                                                                                   .SingleOrDefault();

                var mustHideController = MustHide(controllerSwaggerUIVisibilityAttribute?.Visibility);

                if (mustHideController && controllerSwaggerUIVisibilityAttribute != null)
                {
                    // TODO: Hide controller. How?
                    //controllerSwaggerUIVisibilityAttribute.IgnoreApi = true;
                }

                var mustHideMethod = MustHide(methodSwaggerUIVisibilityAttribute?.Visibility);

                if (mustHideMethod)
                {
                    var route = "/" + apiDescription.RelativePath.TrimEnd('/');
                    swaggerDoc.Paths.Remove(route);
                }
            }
        }

        #endregion

        #region Private Methods

        private bool MustHide(SwaggerUIVisibility? visibility)
        {
            return visibility switch
            {
                SwaggerUIVisibility.Debug => _swaggerUIVisibility != SwaggerUIVisibility.Debug,
                SwaggerUIVisibility.Internal => _swaggerUIVisibility != SwaggerUIVisibility.Debug
                                             && _swaggerUIVisibility != SwaggerUIVisibility.Internal,
                SwaggerUIVisibility.Public => _swaggerUIVisibility != SwaggerUIVisibility.Debug
                                           && _swaggerUIVisibility != SwaggerUIVisibility.Internal
                                           && _swaggerUIVisibility != SwaggerUIVisibility.Public,
                _ => false
            };
        }

        #endregion
    }
}

Registration in Startup:

services.AddSwaggerGen(options =>
   {
      [...]
      options.DocumentFilter<SwaggerUIVisibilityFilter>(SwaggerUIVisibility.Internal);
   });

The SwaggerUIVisibilityAttribute attribute can be set for classes as well as methods. Everything works fine to hide methods.

Issue: I couldn't find a way to remove the controller entirely. I think my question is: How can I remove a controller to NOT show up in SwaggerUI without having to set the [ApiExplorerSettings(IgnoreApi = true)] attribute, which has to be set at compile time?

What I've tried:

  • Let SwaggerUIVisibilityAttribute extend ApiExplorerSettingsAttribute and set IgnoreApi = true in the filter when the condition to hide the controller is met. Result: It is still being displayed (I guess I'm too late in the pipeline)
  • In SwaggerUIVisibilityFilter.Apply, remove the controller from DocumentFilterContext.ApiDescriptions. Result: Not possible as this property is a get only IEnumerable
like image 708
Philippe Avatar asked Nov 15 '25 13:11

Philippe


1 Answers

It's simple. Put the following attribute above any action or controller you want to hide:

[ApiExplorerSettings(IgnoreApi = true)]
like image 58
Shadi Namrouti Avatar answered Nov 18 '25 15:11

Shadi Namrouti



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!