programing

Swashbuckle을 사용하여 WebAPI의 Swagger 문서에서 메서드를 생략하는 방법

muds 2023. 4. 21. 21:32
반응형

Swashbuckle을 사용하여 WebAPI의 Swagger 문서에서 메서드를 생략하는 방법

C# ASP를 가지고 있습니다.스와시버클을 사용하여 API 문서가 자동으로 생성되는 NET WebAPI 응용 프로그램.설명서에서 특정 방법을 생략하고 싶은데 Swagger UI 출력에 포함하지 않도록 Swagger에게 어떻게 말해야 할지 모르겠습니다.

모델 또는 스키마 필터를 추가하는 것과 관련이 있다고 생각합니다만, 어떻게 해야 할지 명확하지 않습니다.또, 메뉴얼에서는, 출력으로부터 완전하게 삭제하는 것이 아니고, 메서드의 출력을 변경하는 방법의 예에 지나지 않는 것 같습니다.

컨트롤러 및 작업에 다음 속성을 추가하여 생성된 문서에서 제외할 수 있습니다.[ApiExplorerSettings(IgnoreApi = true)]

누군가에게 도움이 될 수 있지만, 개발(디버깅) 중에는 컨트롤러나 액션 전체를 공개하고 나서 실가동(릴리스 빌드) 중에는 숨기고 싶다.

#if DEBUG
    [ApiExplorerSettings(IgnoreApi = false)]
#else
    [ApiExplorerSettings(IgnoreApi = true)]
#endif  

누가 github에 솔루션을 올렸기 때문에 여기에 붙여보겠습니다.모든 크레딧은 그에게 돌아간다.https://github.com/domaindrivendev/Swashbuckle/issues/153#issuecomment-213342771

먼저 Attribute 클래스를 만듭니다.

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class HideInDocsAttribute : Attribute
{
}

그런 다음 Document Filter 클래스를 만듭니다.

public class HideInDocsFilter : IDocumentFilter
{
    public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
    {
        foreach (var apiDescription in apiExplorer.ApiDescriptions)
        {
            if (!apiDescription.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<HideInDocsAttribute>().Any() && !apiDescription.ActionDescriptor.GetCustomAttributes<HideInDocsAttribute>().Any()) continue;
            var route = "/" + apiDescription.Route.RouteTemplate.TrimEnd('/');
            swaggerDoc.paths.Remove(route);
        }
    }
}

그런 다음 Swagger Config 클래스에서 해당 문서 필터를 추가합니다.

public class SwaggerConfig
{
    public static void Register(HttpConfiguration config)
    {
        var thisAssembly = typeof(SwaggerConfig).Assembly;

        config
             .EnableSwagger(c =>
                {
                    ...                       
                    c.DocumentFilter<HideInDocsFilter>();
                    ...
                })
            .EnableSwaggerUi(c =>
                {
                    ...
                });
    }
}

마지막 단계는 Swashbuckle에서 문서를 생성하지 않을 컨트롤러 또는 메서드에 [HideInDocsAttribute] 속성을 추가하는 것입니다.

문서 필터로 생성된 후 스웨거 문서에서 "작업"을 제거할 수 있습니다. 동사를 다음과 같이 설정하십시오.null(단, 다른 방법도 있을 수 있습니다)

다음 샘플에서는GET동사 - 이 에서 발췌한 것입니다.

class RemoveVerbsFilter : IDocumentFilter
{
    public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
    {
        foreach (PathItem path in swaggerDoc.paths.Values)
        {
            path.delete = null;
            //path.get = null; // leaving GET in
            path.head = null;
            path.options = null;
            path.patch = null;
            path.post = null;
            path.put = null;
        }
    }
}

그리고 당신의 스웨거 구성:

...EnableSwagger(conf => 
{
    // ...

    conf.DocumentFilter<RemoveVerbsFilter>();
});

경로 항목의 사전 항목을 완전히 제거하는 것이 좋습니다.

var pathsToRemove = swaggerDoc.Paths
                .Where(pathItem => !pathItem.Key.Contains("api/"))
                .ToList();

foreach (var item in pathsToRemove)
{
    swaggerDoc.Paths.Remove(item.Key);
}

이 방법을 사용하면 생성된 swagger.json 정의에서 "빈" 항목이 나타나지 않습니다.

필터를 만들다

public class SwaggerTagFilter : IDocumentFilter
{
    public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
    {
        foreach(var contextApiDescription in context.ApiDescriptions)
        {
            var actionDescriptor = (ControllerActionDescriptor)contextApiDescription.ActionDescriptor;
            
            if(!actionDescriptor.ControllerTypeInfo.GetCustomAttributes<SwaggerTagAttribute>().Any() && 
               !actionDescriptor.MethodInfo.GetCustomAttributes<SwaggerTagAttribute>().Any())
            {
                var key = "/" + contextApiDescription.RelativePath.TrimEnd('/');
                swaggerDoc.Paths.Remove(key);
            }
        }
    }
}

속성 만들기

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class SwaggerTagAttribute : Attribute
{
}

startup.cs에서 신청하세요.

services.AddSwaggerGen(c => {
    c.SwaggerDoc(1, new Info { Title = "API_NAME", Version = "API_VERSION" });
    c.DocumentFilter<SwaggerTagFilter>(); // [SwaggerTag]
});

Swagger JSON에 포함할 메서드 및 컨트롤러에 [SwaggerTag] 속성 추가

@aleha처럼 실수로 엔드포인트를 노출하지 않고(기본적으로 보안) OpenApiDocument를 사용하는 최신 버전의 Swagger를 사용할 수 있도록 기본적으로 제외하려고 했습니다.

ShowInSwagger 속성 생성

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class ShowInSwaggerAttribute : Attribute
{}

그런 다음 문서 필터를 만듭니다.

using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Reflection;
using System;
using System.Linq;
using TLS.Common.Attributes;

namespace TLS.Common.Filters
{
    public class ShowInSwaggerFilter : IDocumentFilter
    {
        public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
        {
            foreach (var contextApiDescription in context.ApiDescriptions)
            {
                var actionDescriptor = (ControllerActionDescriptor)contextApiDescription.ActionDescriptor;

                if (actionDescriptor.ControllerTypeInfo.GetCustomAttributes<ShowInSwaggerAttribute>().Any() ||
                    actionDescriptor.MethodInfo.GetCustomAttributes<ShowInSwaggerAttribute>().Any())
                {
                    continue;
                }
                else
                {
                    var key = "/" + contextApiDescription.RelativePath.TrimEnd('/');
                    var operation = (OperationType)Enum.Parse(typeof(OperationType), contextApiDescription.HttpMethod, true);

                    swaggerDoc.Paths[key].Operations.Remove(operation);

                    // drop the entire route of there are no operations left
                    if (!swaggerDoc.Paths[key].Operations.Any())
                    {
                        swaggerDoc.Paths.Remove(key);
                    }
                }
            }
        }
    }
}

startup.cs 또는 Configure Services:

public void ConfigureServices(IServiceCollection services)
{
     // other code

    services.AddSwaggerGen(c =>
    {
        c.DocumentFilter<ShowInSwaggerFilter>();
        // other config
    });
}

@spotestedmahns 답변에 기초합니다.내 업무는 그 반대였다.허용된 것만 표시합니다.

프레임워크:NetCore 2.1, Swagger: 3.0

속성 추가

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class ShowInSwaggerAttribute : Attribute
{
}

또한 커스텀 IDocument Filter

public class ShowInSwaggerFilter : IDocumentFilter
{
    public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
    {

        foreach (var contextApiDescription in context.ApiDescriptions)
        {
            var actionDescriptor = (ControllerActionDescriptor) contextApiDescription.ActionDescriptor;

            if (actionDescriptor.ControllerTypeInfo.GetCustomAttributes<ShowInSwaggerAttribute>().Any() ||
                actionDescriptor.MethodInfo.GetCustomAttributes<ShowInSwaggerAttribute>().Any())
            {
                continue;
            }
            else
            {
                var key = "/" + contextApiDescription.RelativePath.TrimEnd('/');
                var pathItem = swaggerDoc.Paths[key];
                if(pathItem == null)
                    continue;

                switch (contextApiDescription.HttpMethod.ToUpper())
                {
                    case "GET":
                        pathItem.Get = null;
                        break;
                    case "POST":
                        pathItem.Post = null;
                        break;
                    case "PUT":
                        pathItem.Put = null;
                        break;
                    case "DELETE":
                        pathItem.Delete = null;
                        break;
                }

                if (pathItem.Get == null  // ignore other methods
                    && pathItem.Post == null 
                    && pathItem.Put == null 
                    && pathItem.Delete == null)
                    swaggerDoc.Paths.Remove(key);
            }
        }
    }
}

Configure Services 코드:

public void ConfigureServices(IServiceCollection services)
{
     // other code

    services.AddSwaggerGen(c =>
    {
        // other configurations
        c.DocumentFilter<ShowInSwaggerFilter>();
    });
}

SwaggerConfig에 한 줄 추가

c.DocumentFilter<HideInDocsFilter>();

...

public class HideInDocsFilter : IDocumentFilter
{
    public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
    { 
        var pathsToRemove = swaggerDoc.Paths
            .Where(pathItem => !pathItem.Key.Contains("api/"))
            .ToList();
    
        foreach (var item in pathsToRemove)
        {
            swaggerDoc.Paths.Remove(item.Key);
        }
    }
}

컨트롤러 레벨과 메서드 레벨 모두에서 커스텀필터를 생성할 수 있습니다.따라서 Swagger 문서에서 귀하의 속성을 가진 컨트롤러/메서드를 사용할 수 있습니다.또한 이 필터는 문서에서 중복된 HTTP 동사를 제거했지만(이 예에서는 GET/PUT/POST/PATCH 전용으로 만듭니다), 언제든지 요건에 따라 사용자 정의할 수 있습니다.

아트리뷰트

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class PublicApi:Attribute
{

}

문서 필터

public class PublicApiFilter : IDocumentFilter
{
    public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer)
    {

        var publicPaths = new List<string> {"/api"};

        var publicApiDescriptions = new List<ApiDescription>();

        var publicMethods = FilterByPublicControllers(swaggerDoc, apiExplorer, publicPaths, publicApiDescriptions);

        FilterByPublicActions(swaggerDoc, publicApiDescriptions, publicMethods);
    }

    private static Dictionary<string, List<string>> FilterByPublicControllers(SwaggerDocument swaggerDoc, IApiExplorer apiExplorer, List<string> publicPaths, List<ApiDescription> publicApiDescriptions)
    {
        var publicMethods = new Dictionary<string, List<string>>();
        foreach (var apiDescription in apiExplorer.ApiDescriptions)
        {
            var isPublicApiController = apiDescription.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<PublicApi>().Any();
            var isPublicApiMethod = apiDescription.ActionDescriptor.GetCustomAttributes<PublicApi>().Any();


            if (!isPublicApiController && !isPublicApiMethod)
            {
                continue;
            }

            var relativePath = ToRelativePath(apiDescription);

            publicPaths.Add(relativePath);
            publicApiDescriptions.Add(apiDescription);

            var action = apiDescription.ActionDescriptor.ActionName;
            List<string> available = null;
            if (!publicMethods.TryGetValue(relativePath, out available))
                publicMethods[relativePath] = new List<string>();
            publicMethods[relativePath].Add(action);
        }

        swaggerDoc.paths = swaggerDoc.paths.Where(pair => publicPaths.Contains(pair.Key))
            .ToDictionary(pair => pair.Key,
                pair => pair.Value);
        return publicMethods;
    }

    private static void FilterByPublicActions(SwaggerDocument swaggerDoc, List<ApiDescription> publicApis, Dictionary<string, List<string>> publicMethods)
    {
        foreach (var api in publicApis)
        {
            var relativePath = ToRelativePath(api);
            var availableActions = publicMethods[relativePath];
            if (availableActions == null)
            {
                continue;
            }

            foreach (var path in swaggerDoc.paths.Where(pair => pair.Key.IndexOf(relativePath) > -1).ToList())
            {
                if (!availableActions.Contains("Get"))
                    path.Value.get = null;
                if (!availableActions.Contains("Post"))
                    path.Value.post = null;
                if (!availableActions.Contains("Put"))
                    path.Value.put = null;
                if (!availableActions.Contains("Patch"))
                    path.Value.patch = null;
            }
        }
    }

    private static string ToRelativePath(ApiDescription apiDescription)
    {
        return "/" + apiDescription.RelativePath.Substring(0,apiDescription.RelativePath.LastIndexOf('/'));
    }
}

마지막으로 Swagger Config를 등록합니다.

public class SwaggerConfig
{
    public static void Register()
    {

        var thisAssembly = typeof(SwaggerConfig).Assembly;
        GlobalConfiguration.Configuration
            .EnableSwagger(c =>
                {
                    c.SingleApiVersion("v1", "Reports");
                    c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
                    c.DocumentFilter<PublicApiFilter>();
                })
            .EnableSwaggerUi(c =>
                {

                });

    }
}

컨트롤러

[PublicApi]
public class ProfileController : ApiController

방법

 public class UserController : ApiController
 {
    [PublicApi]
    public ResUsers Get(string sessionKey, int userId, int groupId) {
        return Get(sessionKey, userId, groupId, 0);
    }

최소 API를 사용하는 경우 다음을 사용할 수 있습니다.

app.MapGet("/hello", () => "Hello World!").ExcludeFromDescription();

접근방식을 사용하는 Minimal API를 사용할 수 ..ExcludeFromDescription();"Endpoint Builder" "Endpoint Builder" 입니다.GET 인사하다

app.MapGet("/greeting", () => "Hello World!").ExcludeFromDescription();

매뉴얼은 Route Handler Builder 입니다.Exclude From Description(제외처 설명)

언급URL : https://stackoverflow.com/questions/29701573/how-to-omit-methods-from-swagger-documentation-on-webapi-using-swashbuckle

반응형