자습서: REST API 클라이언트 생성

REST API를 사용하는 애플리케이션은 매우 일반적인 시나리오에 속합니다. 일반적으로 애플리케이션에서 REST API를 호출하는 데 사용할 수 있는 클라이언트 코드를 생성해야 합니다. 이 자습서에서는 MSBuild를 사용하여 빌드 프로세스를 진행하는 중에 REST API 클라이언트를 자동으로 생성하는 방법을 알아봅니다. REST API에 대한 클라이언트 코드를 생성하는 도구인 NSwag를 사용합니다.

전체 샘플 코드는 GitHub .NET 샘플 리포지토리의 REST API 클라이언트 생성에서 사용할 수 있습니다.

이 예제에서는 OpenAPI 사양을 게시하는 공용 Pet Store API를 사용하는 콘솔 앱을 보여 줍니다.

이 자습서에서는 작업, 대상, 속성 또는 런타임과 같은 MSBuild 용어에 대한 기본 지식을 가정합니다. 필요한 배경 정보는 MSBuild 개념 문서를 참조하세요.

빌드의 일부로 명령줄 도구를 실행하려는 경우, 고려해야 할 방법으로는 두 가지가 있습니다. 하나는 명령줄 도구를 실행하고 해당 매개 변수를 지정할 수 있는 MSBuild Exec 작업을 사용하는 것입니다. 다른 하나는 ToolTask에서 파생된 사용자 지정 작업을 만드는 것이며, 이를 통해 더 강력하게 제어할 수 있습니다.

필수 조건

작업, 대상, 속성과 같은 MSBuild 개념을 이해해야 합니다. MSBuild 개념을 참조하십시오.

예제에는 Visual Studio와 함께 설치되는 MSBuild가 필요하지만 MSBuild를 별도로 설치할 수도 있습니다. Visual Studio 없이 MSBuild 다운로드를 참조하십시오.

옵션 1: Exec 작업

Exec 작업은 지정된 인수를 사용하여 지정된 프로세스를 호출하고, 이 프로세스가 완료될 때까지 대기한 다음, 프로세스가 성공적으로 완료되면 true를 반환하고 오류가 발생하면 false를 반환합니다.

NSwag 코드 생성은 MSBuild에서 사용할 수 있습니다. NSwag.MSBuild를 참조하세요.

전체 코드는 PetReaderExecTaskExample 폴더에 있습니다. 다운로드하면 살펴볼 수 있습니다. 이 자습서에서는 단계별 안내를 통해 진행 중인 개념을 알아봅니다.

  1. PetReaderExecTaskExample이라는 새 콘솔 애플리케이션을 만듭니다. .NET 6.0 또는 이후 버전을 사용합니다.

  2. 동일한 솔루션 PetShopRestClient에서 다른 프로젝트를 만듭니다(이 솔루션은 생성된 클라이언트를 라이브러리로 포함할 예정입니다). 이 프로젝트의 경우 .NET Standard 2.1을 사용합니다. 생성된 클라이언트는 .NET Standard 2.0에서 컴파일되지 않습니다.

  3. PetReaderExecTaskExample 프로젝트에서 프로젝트 종속성을 PetShopRestClient 프로젝트에 추가합니다.

  4. PetShopRestClient 프로젝트에 다음 NuGet 패키지를 포함합니다.

    • MSBuild의 코드 생성기에 액세스할 수 있는 Nswag.MSBuild
    • 생성된 클라이언트를 컴파일하는 데 필요한 Newtonsoft.Json
    • 생성된 클라이언트를 컴파일하는 데 필요한 System.ComponentModel.Annotations
  5. PetShopRestClient 프로젝트에서 코드 생성을 위해 하나의 폴더(PetShopRestClient)를 추가하고 자동으로 생성된 Class1.cs를 삭제합니다.

  6. 프로젝트 루트에 petshop-openapi-spec.json이라는 텍스트 파일을 만듭니다. 여기에서 OpenApi 사양을 복사하여 파일에 저장합니다. 빌드하는 동안 사양의 스냅샷을 온라인으로 읽는 대신 복사하는 것이 가장 좋습니다. 입력에만 의존하여 일관되게 재현 가능한 빌드가 항상 필요합니다. API를 직접 사용하는 경우 오늘 작동하는 빌드를 동일한 원본에서 내일 실패하는 빌드로 변환할 수 있습니다. petshop-openapi-spec.json에 저장된 스냅샷을 사용하면 사양이 변경되더라도 빌드되는 버전을 계속 가질 수 있습니다.

  7. 그런 다음, PetShopRestClient.csproj를 수정하고 빌드 프로세스 중에 클라이언트를 생성하는 MSBuild 대상을 추가합니다.

    먼저 클라이언트 생성에 유용한 몇 가지 속성을 추가합니다.

     <PropertyGroup>
         <PetOpenApiSpecLocation>petshop-openapi-spec.json</PetOpenApiSpecLocation>
         <PetClientClassName>PetShopRestClient</PetClientClassName>
         <PetClientNamespace>PetShopRestClient</PetClientNamespace>
         <PetClientOutputDirectory>PetShopRestClient</PetClientOutputDirectory>
     </PropertyGroup>
    

    다음 대상을 추가합니다.

     <Target Name="generatePetClient" BeforeTargets="CoreCompile" Inputs="$(PetOpenApiSpecLocation)" Outputs="$(PetClientOutputDirectory)\$(PetClientClassName).cs">
         <Exec Command="$(NSwagExe) openapi2csclient /input:$(PetOpenApiSpecLocation)  /classname:$(PetClientClassName) /namespace:$(PetClientNamespace) /output:$(PetClientOutputDirectory)\$(PetClientClassName).cs" ConsoleToMSBuild="true">
         <Output TaskParameter="ConsoleOutput" PropertyName="OutputOfExec" />
       </Exec>
     </Target>
     <Target Name="forceReGenerationOnRebuild" AfterTargets="CoreClean">
        <Delete Files="$(PetClientOutputDirectory)\$(PetClientClassName).cs"></Delete>
     </Target>
    

    이 대상은 빌드 순서를 정의하는 방법으로 BeforeTarget 및 AfterTarget 특성을 사용합니다. generatePetClient라는 이름의 첫 번째 대상은 핵심 컴파일 대상보다 먼저 실행되므로 컴파일러가 실행되기 전에 원본이 만들어집니다. 입력 및 출력 매개 변수는 증분 빌드와 관련이 있습니다. MSBuild는 입력 파일의 타임스탬프를 출력 파일의 타임스탬프와 비교하고 대상을 건너뛰거나, 빌드하거나, 부분적으로 다시 빌드할지 결정할 수 있습니다.

    프로젝트에 NSwag.MSBuild NuGet 패키지를 설치한 후 .csproj 파일의 변수 $(NSwagExe)를 사용하여 MSBuild 대상에서 NSwag 명령줄 도구를 실행할 수 있습니다. 이렇게 하면 NuGet을 통해 도구를 쉽게 업데이트할 수 있습니다. 여기서는 Exec MSBuild 작업을 사용하여 클라이언트 Rest Api를 생성하는 데 필요한 매개 변수를 이용해 NSwag 프로그램을 실행합니다. NSwag 명령 및 매개 변수를 참조하세요.

    출력을 캡처하려는 경우, <Exec>ConsoleToMsBuild="true"<Exec> 태그에 추가한 다음 <Output> 태그의 ConsoleOutput 매개 변수를 사용하여 출력을 캡처하면 됩니다. ConsoleOutput은 출력을 Item으로 반환합니다. 공백이 잘립니다. ConsoleToMSBuild가 true일 때 ConsoleOutput이 활성화됩니다.

    forceReGenerationOnRebuild라는 이름의 두 번째 대상은 정리 중에 생성된 클래스를 삭제하여 대상 다시 빌드를 실행하는 동안 생성된 코드를 강제로 다시 생성합니다. 이 대상은 CoreClean MSBuild 미리 정의된 대상 다음에 실행됩니다.

  8. Visual Studio 솔루션 다시 빌드를 실행하고 PetShopRestClient 폴더에 생성된 클라이언트를 확인합니다.

  9. 이제 생성된 클라이언트를 사용합니다. 클라이언트 Program.cs로 이동하여 다음 코드를 복사합니다.

    using System;
    using System.Net.Http;
    
    namespace PetReaderExecTaskExample
    {
       internal class Program
       {
           private const string baseUrl = "https://petstore.swagger.io/v2";
           static void Main(string[] args)
           {
               HttpClient httpClient = new HttpClient();
               httpClient.BaseAddress = new Uri(baseUrl);
               var petClient = new PetShopRestClient.PetShopRestClient(httpClient);
               var pet = petClient.GetPetByIdAsync(1).Result;
               Console.WriteLine($"Id: {pet.Id} Name: {pet.Name} Status: {pet.Status} CategoryName: {pet.Category.Name}");
           }
       }
    }
    

    참고 항목

    이 코드는 간단하게 시연할 수 있지만 실제 코드에 대한 모범 사례는 아니기 때문에 new HttpClient()를 사용합니다. 가장 좋은 방법은 HttpClientFactory를 사용하여 리소스 소모 또는 부실 DNS 문제와 같은 HttpClient 요청의 알려진 문제를 해결하는 HttpClient 개체를 만드는 것입니다. IHttpClientFactory를 사용하여 복원력 있는 HTTP 요청 구현을 참조하십시오.

축하합니다! 이제 프로그램을 실행하여 작동 방식을 확인할 수 있습니다.

옵션 2: ToolTask에서 파생된 사용자 지정 작업

대부분의 경우, Exec 작업을 사용하면 REST API 클라이언트 코드 생성과 같은 작업을 수행할 외부 도구를 충분히 실행할 수 있습니다. 그러나 Windows 경로를 입력으로 사용하지 않는 경우에만 REST API 클라이언트 코드 생성을 허용하려면 어떻게 해야 할까요? 또는 실행 파일이 있는 위치에서 일정한 방식으로 계산해야 한다면 어떻게 해야 할까요? 추가 작업을 수행하기 위해 일부 코드를 실행해야 하는 상황이 있는 경우, MSBuild 도구 작업이 가장 적합한 솔루션입니다. ToolTask 클래스는 MSBuild Task에서 파생된 추상 클래스입니다. 사용자 지정 MSBuild 작업을 만드는 구체적인 하위 클래스를 정의할 수 있습니다. 이 방법을 사용하면 명령 실행을 준비하는 데 필요한 모든 코드를 실행할 수 있습니다. 먼저 코드 생성을 위한 사용자 지정 작업 만들기 자습서를 읽으시기 바랍니다.

REST API 클라이언트를 생성하는 MSBuild ToolTask에서 파생된 사용자 지정 작업을 만들지만 http 주소를 사용하여 OpenApi 사양을 참조하려고 하면 오류를 내보내도록 설계됩니다. NSwag는 http 주소를 OpenApi 사양 입력으로 지원하지만, 이 예제에서는 이를 허용하지 않는 디자인 요구 사항이 있다고 가정해 보겠습니다.

전체 코드는 이 PetReaderToolTaskExample 폴더에 있는데, 다운로드하면 살펴볼 수 있습니다. 이 자습서에서는 단계별로 진행하여 사용자 고유의 시나리오에 적용할 수 있는 몇 가지 개념을 알아봅니다.

  1. 사용자 지정 작업에 대한 새 Visual Studio 프로젝트를 만듭니다. 이 프로젝트의 이름을 RestApiClientGenerator라 지정하고 .NET Standard 2.0에서 클래스 라이브러리(C#) 템플릿을 사용합니다. 솔루션의 이름을 PetReaderToolTaskExample로 지정합니다.

  2. 자동으로 생성된 Class1.cs를 삭제합니다.

  3. Microsoft.Build.Utilities.Core NuGet 패키지 추가:

    • RestApiClientGenerator라는 이름의 클래스 생성

    • MSBuild ToolTask에서 상속하고 다음 코드에서 볼 수 있는 추상 메서드를 구현합니다.

      using Microsoft.Build.Utilities;
      
      namespace RestApiClientGenerator
      {
          public class RestApiClientGenerator : ToolTask
          {
              protected override string ToolName => throw new System.NotImplementedException();
      
              protected override string GenerateFullPathToTool()
              {
                  throw new System.NotImplementedException();
              }
          }
      }
      
  4. 다음 매개 변수를 추가합니다.

    • InputOpenApiSpec: 사양이 있는 위치
    • ClientClassName: 생성된 클래스의 이름
    • ClientNamespaceName: 클래스가 생성되는 네임스페이스
    • FolderClientClass: 클래스가 위치할 폴더의 경로
    • NSwagCommandFullPath: NSwag.exe가 위치한 디렉터리의 전체 경로
         [Required]
         public string InputOpenApiSpec { get; set; }
         [Required]
         public string ClientClassName { get; set; }
         [Required]
         public string ClientNamespaceName { get; set; }
         [Required]
         public string FolderClientClass { get; set; }
         [Required]
         public string NSwagCommandFullPath { get; set; }
    
  5. NSwag 명령줄 도구를 설치합니다. NSwag.exe가 위치한 디렉터리의 전체 경로가 필요합니다.

  6. 다음과 같이 추상 메서드를 구현합니다.

       protected override string ToolName => "RestApiClientGenerator";
    
       protected override string GenerateFullPathToTool()
       {
           return $"{NSwagCommandFullPath}\\NSwag.exe";
       }
    
  7. 재정의할 수 있는 여러 메서드가 있습니다. 현재 구현의 경우, 다음 두 가지를 정의합니다.

    • 명령 매개 변수를 정의합니다.
      protected override string GenerateCommandLineCommands()
      {
          return $"openapi2csclient /input:{InputOpenApiSpec}  /classname:{ClientClassName} /namespace:{ClientNamespaceName} /output:{FolderClientClass}\\{ClientClassName}.cs";
      }
    
    • 매개 변수 유효성 검사:
    protected override bool ValidateParameters()
    {
          //http address is not allowed
          var valid = true;
          if (InputOpenApiSpec.StartsWith("http:") || InputOpenApiSpec.StartsWith("https:"))
          {
              valid = false;
              Log.LogError("URL is not allowed");
          }
    
          return valid;
    }
    

    참고 항목

    이 간단한 유효성 검사는 MSBuild 파일에서 다른 방법으로 수행할 수 있지만 C# 코드에서 수행하여 명령 및 논리를 캡슐화하는 것이 좋습니다.

  8. 프로젝트를 빌드합니다.

새 MSBuild 작업을 사용하는 콘솔 앱 만들기

다음 단계에서는 작업을 사용하는 앱을 만듭니다.

  1. 콘솔 앱 프로젝트를 만들고 이 프로젝트의 이름을 PetReaderToolTaskConsoleApp라 지정합니다. .NET 6.0을 선택합니다. 시작 프로젝트로 표시합니다.

  2. 클래스 라이브러리 프로젝트를 만들어 PetRestApiClient라는 코드를 생성합니다. .NET Standard 2.1을 사용합니다.

  3. PetReaderToolTaskConsoleApp 프로젝트에서 PetRestApiClient에 대한 프로젝트 종속성을 만듭니다.

  4. PetRestApiClient 프로젝트에서 폴더 PetRestApiClient를 만듭니다. 이 폴더에는 생성된 코드가 포함됩니다.

  5. 자동으로 생성된 Class1.cs를 삭제합니다.

  6. PetRestApiClient에서 다음 NuGet 패키지를 추가합니다.

    • 생성된 클라이언트를 컴파일하는 데 필요한 Newtonsoft.Json
    • 생성된 클라이언트를 컴파일하는 데 필요한 System.ComponentModel.Annotations
  7. PetRestApiClient 프로젝트에서 프로젝트 폴더에 petshop-openapi-spec.json이라는 텍스트 파일을 만듭니다. OpenApi 사양을 추가하려면 여기에서 파일로 콘텐츠를 복사합니다. 앞서 설명한 대로 입력에만 의존하는 재현 가능한 빌드가 좋습니다. 이 예제에서는 사용자가 OpenApi 사양 입력으로 URL을 선택하는 경우 빌드 오류가 발생합니다.

    Important

    일반 다시 빌드는 작동하지 않습니다. RestApiClientGenerator.dll을 복사하거나 삭제할 수 없음을 나타내는 오류가 표시됩니다. 그 이유는 MBuild 사용자 지정 작업을 사용하는 동일한 빌드 프로세스에서 이 작업을 빌드하려고 하기 때문입니다. PetReaderToolTaskConsoleApp을 선택하고 해당 프로젝트만 다시 빌드합니다. 또 다른 솔루션은 자습서: 사용자 지정 작업 예제 만들기에서와 같이 완전히 독립적인 Visual Studio 솔루션에 사용자 지정 작업을 배치하는 것입니다.

  8. 다음 코드를 Program.cs 파일에 복사합니다.

     using System;
     using System.Net.Http;
     namespace PetReaderToolTaskConsoleApp
     {
       internal class Program
       {
           private const string baseUrl = "https://petstore.swagger.io/v2";
           static void Main(string[] args)
           {
               HttpClient httpClient = new HttpClient();
               httpClient.BaseAddress = new Uri(baseUrl);
               var petClient = new PetRestApiClient.PetRestApiClient(httpClient);
               var pet = petClient.GetPetByIdAsync(1).Result;
               Console.WriteLine($"Id: {pet.Id} Name: {pet.Name} Status: {pet.Status} CategoryName: {pet.Category.Name}");
           }
       }
     }
    
  9. 작업을 호출하고 코드를 생성하도록 MSBuild 지침을 변경합니다. 다음 단계에 따라 PetRestApiClient.csproj를 편집합니다.

    1. MSBuild 사용자 지정 작업의 사용을 등록합니다.

      <UsingTask TaskName="RestApiClientGenerator.RestApiClientGenerator" AssemblyFile="..\RestApiClientGenerator\bin\Debug\netstandard2.0\RestApiClientGenerator.dll" />
      
    2. 작업을 실행하는 데 필요한 몇 가지 속성을 추가합니다.

       <PropertyGroup>
          <!--The place where the OpenApi spec is in-->
         <PetClientInputOpenApiSpec>petshop-openapi-spec.json</PetClientInputOpenApiSpec>
         <PetClientClientClassName>PetRestApiClient</PetClientClientClassName>
         <PetClientClientNamespaceName>PetRestApiClient</PetClientClientNamespaceName>
         <PetClientFolderClientClass>PetRestApiClient</PetClientFolderClientClass>
         <!--The directory where NSawg.exe is in-->
         <NSwagCommandFullPath>C:\Nsawg\Win</NSwagCommandFullPath>
        </PropertyGroup>
      

      Important

      시스템에서 설치 위치에 따라 적절한 NSwagCommandFullPath 값을 선택합니다.

    3. 빌드 프로세스 중에 클라이언트를 생성하는 MSBuild 대상을 추가합니다. 컴파일에 사용되는 코드를 생성하기 위해 CoreCompile을 실행하기 전에 이 대상을 실행해야 합니다.

      <Target Name="generatePetClient" BeforeTargets="CoreCompile" Inputs="$(PetClientInputOpenApiSpec)" Outputs="$(PetClientFolderClientClass)\$(PetClientClientClassName).cs">
        <!--Calling our custom task derivated from MSBuild Tool Task-->
        <RestApiClientGenerator InputOpenApiSpec="$(PetClientInputOpenApiSpec)" ClientClassName="$(PetClientClientClassName)" ClientNamespaceName="$(PetClientClientNamespaceName)" FolderClientClass="$(PetClientFolderClientClass)" NSwagCommandFullPath="$(NSwagCommandFullPath)"></RestApiClientGenerator>
      </Target>
      
      <Target Name="forceReGenerationOnRebuild" AfterTargets="CoreClean">
        <Delete Files="$(PetClientFolderClientClass)\$(PetClientClientClassName).cs"></Delete>
      </Target>
      

    InputOutput증분 빌드와 관련이 있으며 forceReGenerationOnRebuild 대상은 CoreClean 다음에 생성된 파일을 삭제합니다. 그러면 다시 빌드 작업 중에 클라이언트가 강제로 다시 생성됩니다.

  10. PetReaderToolTaskConsoleApp을 선택하고 해당 프로젝트만 다시 빌드합니다. 이제 클라이언트 코드가 생성되며 코드가 컴파일됩니다. 이 코드를 실행하여 작동 방식을 확인할 수 있습니다. 이 코드는 하나의 파일에서 코드를 생성하며 허용됩니다.

  11. 이 단계에서는 매개 변수 유효성 검사를 보여줍니다. PetRestApiClient.csproj에서 URL을 사용하도록 속성 $(PetClientInputOpenApiSpec)을 다음과 같이 변경합니다.

      <PetClientInputOpenApiSpec>https://petstore.swagger.io/v2/swagger.json</PetClientInputOpenApiSpec>
    
  12. PetReaderToolTaskConsoleApp을 선택하고 해당 프로젝트만 다시 빌드합니다. 디자인 요구 사항에 따라 ‘URL이 허용되지 않습니다’라는 오류가 표시됩니다.

코드 다운로드

NSwag 명령줄 도구를 설치합니다. 그러면 NSwag.exe가 위치한 디렉터리의 전체 경로가 필요합니다. 그런 다음 PetRestApiClient.csproj를 편집하고 컴퓨터의 설치 경로에 따라 올바른 $(NSwagCommandFullPath) 값을 선택합니다. 이제 RestApiClientGenerator를 선택하고 해당 프로젝트만 빌드한 다음, 마지막으로 PetReaderToolTaskConsoleApp을 선택하고 다시 빌드합니다. PetReaderToolTaskConsoleApp을 실행하여 모든 항목이 예상대로 작동하는지 확인합니다.

다음 단계

필요하다면 사용자 지정 작업을 NuGet 패키지로 게시할 수 있습니다.

또는 사용자 지정 작업을 테스트하는 방법을 알아봅니다.