ASP.NET Core API - 경로 버전 관리 + Swashbuckle

25340 단어 csharpwebdevdotnet

사양



.NET CoreASP.NET Core은 먼 길을 왔으며 따라서 ASP.NET Core API 버전을 지정하는 다양한 도구가 있습니다.

API 엔드포인트의 버전을 지정하는 세 가지 주요 방법이 있습니다.
  • 경로 버전 관리 버전www.some-site.com/v1/potatoes
  • 쿼리 문자열www.some-site.com?api-version=1.0
  • 요청 헤더
  • 의 Http 헤더api-supported-version: 1.0

    경로 버전 관리



    요청 경로는 리소스의 주소입니다. 리소스를 버전화할 때 요청 경로의 버전화는 가장 의미가 있습니다. 선언적이고 읽을 수 있으며 가장 의미를 표현합니다.

    간단한 구현





    먼저 새 ASP.NET Core API 프로젝트를 만들고 다음 Nuget 패키지를 추가합니다.

    Microsoft.AspNetCore.Mvc.Versioning



    이제 controller를 생성하고 다음 엔드포인트를 추가합니다.

    [Route("api/[controller]")]
    [ApiController]
    public class SpaceEmporiumController : ControllerBase
    {
       [HttpGet("MoonRocks")]
       public IActionResult GetMoonRocks() => Ok("Here are some Moon Rocks! v1");
    
       [HttpGet("MoonRocks")]
       public IActionResult GetMoonRocksV2() => Ok("Here are some Moon Rocks! v2");
    }
    


    이제 월석을 얻을 수 있는 두 개의 엔드포인트(버전 1 및 최신 버전 2)가 있습니다. ASP.NET Core는 현재 동일한 경로(및 REST 동사)를 가지고 있기 때문에 이러한 엔드포인트를 설정하는 방법을 모릅니다.

    GET api/SpaceEmporium/MoonRocks



    이제 Microsoft.AspNetCore.Mvc.Versioning을 사용하여 어떤 버전이 어디에 있는지 표시할 수 있습니다.

    [Route("api/v{version:apiVersion}/[controller]")]
    [ApiVersion("1")]
    [ApiVersion("2")]
    [ApiController]
    public class SpaceEmporiumController : ControllerBase
    {
       [MapToApiVersion("1")]
       [HttpGet("MoonRocks")]
       public IActionResult GetMoonRocks() => Ok("Here are some Moon Rocks! v1");
    
       [MapToApiVersion("2")]
       [HttpGet("MoonRocks")]
       public IActionResult GetMoonRocksV2() => Ok("Here are some Moon Rocks! v2");
    }
    




    여기서 몇 가지 간단한 일이 발생합니다.
  • 특성[Route("api/v{version:apiVersion}/[controller]")]은 요청 경로에 버전 특성을 추가하도록 ASP.NET Core에 지시합니다.
  • 속성[ApiVersion("x")]은 이 컨트롤러
  • 에 있는 API 버전을 지정합니다.
  • 특성[MapToApiVersion("x")]은 엔드포인트를 특정 버전
  • 에 매핑합니다.

    이제 두 개의 엔드포인트가 있습니다.

    GET api/v1/SpaceEmporium/MoonRocks
    GET api/v2/SpaceEmporium/MoonRocks



    돌아가는

    "Here are some Moon Rocks! v1"
    "Here are some Moon Rocks! v2"



    각기.

    편의를 위해 마지막으로 한 가지만 추가하겠습니다. Startup.cs 파일 내에서 추가

    public void ConfigureServices(IServiceCollection services)
    {
       services.AddApiVersioning(o =>
       {
          o.AssumeDefaultVersionWhenUnspecified = true;
          o.DefaultApiVersion = new ApiVersion(1, 0);
       });
    }
    


    이제 .ApiVersioning 옵션이 구성되어 전체 애플리케이션에서 버전 관리를 구성할 필요가 없습니다. 컨트롤러 또는 엔드포인트에 버전 관리를 지정하지 않으면 버전 1로 간주됩니다.

    이제 애플리케이션을 실행하고 Postman 또는 cURL 을 사용하여 테스트합니다. 각각 응답과 함께 다음 cURL 명령을 실행할 수 있어야 합니다.

    curl -X GET https://localhost:5001/api/v1/SpaceEmporium/MoonRocks
    Here are some Moon Rocks! v1

    curl -X GET https://localhost:5001/api/v2/SpaceEmporium/MoonRocks
    Here are some Moon Rocks! v2



    엄청난! 이제 API 버전이 관리됩니다. 코드를 쉽게 읽고 유지 관리할 수 있으며 생성되는 경로 버전 관리는 이해하고 사용하기 쉽습니다.



    Swashbuckle을 사용한 Swagger 생성



    이제 Swagger Generation 및 Swashbuckle에서 작동하는 버전 관리에 집중하겠습니다.

    먼저 다음 Nuget 패키지를 추가합니다.
  • 스워시버클.AspNetCore.Swagger
  • 스워시버클.AspNetCore.SwaggerGen
  • 스워시버클.AspNetCore.SwaggerUI

  • 이제 Swashbuckle이 실제로 무슨 일이 일어나고 있는지 이해하려면 두 가지 필터를 구현해야 합니다.
  • RemoveVersionFromParameter
  • ReplaceVersionWithExactValueInPath
  • RemoveVersionFromParameter[Route("api/v{version:apiVersion}/[controller]")] 속성의 결과로 생성된 Swagger 문서에서 버전 매개변수를 제거합니다.
    ReplaceVersionWithExactValueInPath 경로의 버전 변수를 정확한 값(예: v1, v2.

    public class RemoveVersionFromParameter : IOperationFilter
    {
       public void Apply(OpenApiOperation operation, OperationFilterContext context)
       {
          if (!operation.Parameters.Any())
             return;
    
          var versionParameter = operation.Parameters.Single(p => p.Name == "version");
          operation.Parameters.Remove(versionParameter);
       }
    }
    


    그리고

    public class ReplaceVersionWithExactValueInPath : IDocumentFilter
    {
       public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
       {
          var paths = new OpenApiPaths();
    
          foreach(var (key, value) in swaggerDoc.Paths)
             paths.Add(key.Replace("v{version}", swaggerDoc.Info.Version), value);
    
          swaggerDoc.Paths = paths;
       }
    }
    

    Startup.cs 파일에 다음을 추가합니다.

    public void ConfigureServices(IServiceCollection services)
    {
       services.AddApiVersioning(o =>
       {
          o.AssumeDefaultVersionWhenUnspecified = true;  
          o.DefaultApiVersion = new ApiVersion(1, 0);
    
       });
       services.AddControllers();
       services.AddSwaggerGen(configureSwaggerGen);
    }
    
    private static void configureSwaggerGen(SwaggerGenOptions options)
    {
       addSwaggerDocs(options);
    
       options.OperationFilter<RemoveVersionFromParameter>();
       options.DocumentFilter<ReplaceVersionWithExactValueInPath>();
    
       options.DocInclusionPredicate((version, desc) =>
       {
          if (!desc.TryGetMethodInfo(out var methodInfo))
             return false;
    
          var versions = methodInfo
             .DeclaringType?
         .GetCustomAttributes(true)
         .OfType<ApiVersionAttribute>()
         .SelectMany(attr => attr.Versions);
    
          var maps = methodInfo
             .GetCustomAttributes(true)
         .OfType<MapToApiVersionAttribute>()
         .SelectMany(attr => attr.Versions)
         .ToList();
    
          return versions?.Any(v => $"v{v}" == version) == true
                   && (!maps.Any() || maps.Any(v => $"v{v}" == version));
       });
    }
    
    private static void addSwaggerDocs(SwaggerGenOptions options)
    {
       options.SwaggerDoc("v1", new OpenApiInfo
       {
          Version = "v1",
          Title = "Space Emporium API",
          Description = "API for the Space Emporium",
       });
    
       options.SwaggerDoc("v2", new OpenApiInfo
       {
          Version = "v2",
          Title = "Space Emporium API",
          Description = "API for the Space Emporium",
       });
    }
    
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
       ...
       app.UseSwagger(c => { c.RouteTemplate = "dev/swagger/{documentName}/swagger.json"; });
       app.UseSwaggerUI(options =>
       {         
          options.SwaggerEndpoint("/dev/swagger/v1/swagger.json", "Space Emporium API v1");
          options.SwaggerEndpoint("/dev/swagger/v2/swagger.json", "Space Emporium API v2");
          options.RoutePrefix = "dev/swagger";
       });
       ...
    }
    


    이렇게 하면 v1 및 v2 Swagger 문서가 생성됩니다. localhost:5001/dev/swagger에서 호스팅됩니다.

    이제 두 Swagger 문서가 모두 작동하고 다음이 표시되어야 합니다.





    작은 속임수


    Properties/launchSettings.json 내에서 다음 프로필을 추가합니다.

      "profiles": {
        "IIS Express": {
          "commandName": "IISExpress",
          "launchBrowser": true,
          "launchUrl": "dev/swagger",
          "environmentVariables": {
            "ASPNETCORE_ENVIRONMENT": "Development"
          }
        },
        "SpaceEmporium": {
          "commandName": "Project",
          "launchBrowser": true,
          "launchUrl": "dev/swagger",
          "applicationUrl": "https://localhost:5001;http://localhost:5000",
          "environmentVariables": {
            "ASPNETCORE_ENVIRONMENT": "Development"
          }
        }
      }
    


    이렇게 하면 Swagger 페이지에서 바로 애플리케이션이 시작됩니다.

    폐쇄



    ASP.NET Core의 경로 버전 관리는 강력하고 구현하기 쉽습니다. 버전 관리로 Swagger 생성을 구현하면 관련 Swagger 문서를 통해 API를 사용하는 사람에게 버전 관리 권한이 부여됩니다.



    SpaceEmporium Versioning App on Github

    좋은 웹페이지 즐겨찾기