ASP.NET Web API와 라우팅

등록일시: 2013-07-10 20:30,  수정일시: 2014-01-01 12:03
조회수: 9,138
이 문서는 ASP.NET Web API 기술을 널리 알리고자 하는 개인적인 취지로 제공되는 번역문서입니다. 이 문서에 대한 모든 저작권은 마이크로소프트에 있으며 요청이 있을 경우 언제라도 게시가 중단될 수 있습니다. 번역 내용에 오역이 존재할 수 있고 주석은 번역자 개인의 의견일 뿐이며 마이크로소프트는 이에 관한 어떠한 보장도 하지 않습니다. 번역이 완료된 이후에도 대상 제품 및 기술이 개선되거나 변경됨에 따라 원문의 내용도 변경되거나 보완되었을 수 있으므로 주의하시기 바랍니다.

본 자습서에서는 ASP.NET Web API가 HTTP 요청을 컨트롤러로 라우팅하는 방법을 살펴봅니다.

여러분이 ASP.NET MVC에 익숙하다면, Web API의 라우팅과 MVC의 라우팅이 매우 비슷하다는 점을 알 수 있을 것입니다. Web API 입장에서 가장 큰 차이점은 액션을 선택할 때, URI 경로 대신 HTTP 메서드를 이용한다는 점입니다. 그러나, 원한다면 Web API에서도 MVC 스타일의 라우팅을 사용할 수도 있습니다. 참고로 본 자습서는 ASP.NET MVC에 관한 어떠한 지식도 전제로 하지 않습니다.

라우팅 테이블

ASP.NET Web API에서 컨트롤러는 HTTP 요청을 처리하는 클래스입니다. 그리고, 이런 컨트롤러의 public 메서드들을 액션 메서드 또는 간단하게 액션이라고 부릅니다. Web API 프레임워크는 HTTP 요청을 받으면, 해당 요청을 바로 이 액션으로 라우트합니다.

Web API 프레임워크는 호출할 액션을 결정하기 위해서 라우팅 테이블을 이용합니다. 예를 들어서, Web API를 위한 Visual Studio 프로젝트 템플릿은 다음과 같은 기본 라우트를 자동으로 생성해줍니다:

routes.MapHttpRoute(
    name: "API Default",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

이 기본 라우트는 App_Start 디렉터리에 위치해 있는 WebApiConfig.cs 파일에 정의되어 있습니다:

WebApiConfig 클래스에 대한 보다 자세한 정보는 Configuring ASP.NET Web API 문서를 참고하시기 바랍니다.

만약, Web API를 자체 호스트(Self-Host)하고 싶다면, 직접 HttpSelfHostConfiguration 개체에 라우팅 테이블을 설정해야만 합니다. 자체 호스트에 대한 보다 자세한 정보는 자체-호스트(Self-Host) Web API (C#) 문서를 참고하시기 바랍니다.

라우팅 테이블의 각 항목들은 라우팅 템플릿을 갖고 있습니다. 가령, 방금 살펴본 Web API의 기본 라우트 템플릿은 "api/{controller}/{id}"입니다. 이 라우트 템플릿에서 "api"는 리터럴 경로 세그먼트이고, {controller} 와 {id}는 위치지정자 변수들입니다.

Web API 프레임워크는 HTTP 요청을 받으면 URI와 일치하는 라우트 템플릿이 라우팅 테이블에 존재하는지 여부를 확인합니다. 만약 일치하는 템플릿이 존재하지 않으면, 클라이언트는 404 오류를 반환받게 됩니다. 예를 들어서, 다음의 URI들은 기본 라우트와 일치합니다:

  • /api/contacts
  • /api/contacts/1
  • /api/products/gizmo1

그러나, 다음의 URI는 "api" 세그먼트가 존재하지 않으므로 일치하지 않습니다:

  • /contacts/1

노트: 굳이 라우트에 "api"를 사용하는 이유는 ASP.NET MVC의 라우팅과 충돌할 수 있는 가능성을 최소화하기 위한 것입니다. 이 방식을 적용하면 MVC 컨트롤러에 대해서는, "/contacts"를 사용하고 Web API 컨트롤러에 대해서는 "/api/contacts"를 사용하는 식으로 활용이 가능합니다. 물론, 이 규약이 마음에 들지 않으면 기본 라우트 테이블을 변경해도 됩니다.

일치하는 라우트가 발견되면, Web API는 컨트롤러와 액션을 선택합니다:

  1. Web API는 컨트롤러를 찾기 위해서 {controller} 변수값 뒤에 "Controller"라는 문자열을 추가합니다.
  2. Web API는 액션을 찾기 위해서 HTTP 메서드를 살펴본 다음, HTTP 메서드 이름과 같은 이름으로 시작하는 액션을 찾습니다. 가령, GET 요청인 경우라면 "GetContact"나 "GetAllContacts" 같이 "Get..."으로 시작하는 액션을 찾습니다. 이 규약은 오직 GET, POST, PUT, DELETE 메서드만을 대상으로만 적용되는데, 컨트롤러에 어트리뷰트를 지정해서 다른 HTTP 메서드에 대해서도 이 규약을 적용시킬 수 있습니다. 이에 관해서는 잠시 뒤에 예제를 살펴볼 것입니다.
  3. {id} 등과 같은 라우트 템플릿의 다른 위치지정자 변수들은 액션의 매개변수에 맵핑됩니다.

그러면, 실제로 예제를 한 번 살펴보도록 하겠습니다. 가령, 다음과 같은 컨트롤러를 정의했다고 가정합니다:

public class ProductsController : ApiController
{
    public void GetAllProducts() { }
    public IEnumerable<Product> GetProductById(int id) { }
    public HttpResponseMessage DeleteProduct(int id){ }
}

그리고, 다음은 몇 가지 사용 가능한 HTTP 요청과 각 요청에 의해서 호출되는 액션들입니다:

HTTP 메서드 URI 경로 액션 매개변수
GET api/products GetAllProducts (없음)
GET api/products/4 GetProductById 4
DELETE api/products/4 DeleteProduct 4
POST api/products (일치하는 액션이 없음)  

이 예제에서 URI에 {id} 세그먼트가 존재하는 경우, 액션의 id 매개변수에 맵핑되고 있는 점에 주목하시기 바랍니다. 가령, 컨트롤러에는 두 개의 GET 메서드가 정의되어 있으며, 그 중 하나에는 id 매개변수가 존재하고 나머지 하나에는 매개변수가 존재하지 않습니다.

그리고, POST 요청은 실패하게 되는데, 이는 컨트롤러에 "Post..."로 시작되는 이름의 메서드가 없기 때문입니다.

라우팅 변수

지금까지 ASP.NET Web API의 기본적인 라우팅 메커니즘을 살펴봤습니다. 이번에는 몇 가지 변형된 사례를 살펴보겠습니다.

HTTP 메서드

HTTP 메서드에 관한 이름 규약을 적용하는 대신, HttpGet, HttpPut, HttpPost, HttpDelete 어트리뷰트를 사용해서 명시적으로 액션 메서드에 관련 HTTP 메서드를 지정할 수 있습니다.

가령, 다음 예제의 경우, FindProduct 메서드는 GET 요청에 맵핑됩니다:

public class ProductsController : ApiController
{
    [HttpGet]
    public Product FindProduct(id) {}
}

액션에 여러 개의 HTTP 메서드를 허용하거나, GET, PUT, POST, DELETE 외의 HTTP 메서드를 허용하려면, 매개변수로 HTTP 메서드들의 목록을 받는 AcceptVerbs 어트리뷰트를 사용하면 됩니다.

public class ProductsController : ApiController
{
    [AcceptVerbs("GET", "HEAD")]
    public Product FindProduct(id) { }
 
    // WebDAV 메서드
    [AcceptVerbs("MKCOL")]
    public void MakeCollection() { }
}

액션 이름에 따른 라우팅

기본 라우팅 템플릿은 액션을 선택하기 위해서 HTTP 메서드를 이용합니다. 그러나, URI에서 액션 이름을 추출하도록 새로운 라우트를 작성할 수도 있습니다:

routes.MapHttpRoute(
    name: "ActionApi",
    routeTemplate: "api/{controller}/{action}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

이 라우트 템플릿에서는 {action} 매개변수가 컨트롤러의 액션 메서드 이름을 나타냅니다. 이런 형태의 라우팅을 사용하는 경우에는, HTTP 메서드의 허용 여부를 제어하려면 어트리뷰트를 사용해야 합니다. 가령, 컨트롤러에 다음과 같은 메서드가 존재한다고 가정해보겠습니다:

public class ProductsController : ApiController
{
    [HttpGet]
    public string Details(int id);
}

결과적으로 "api/products/details/1"에 대한 HTTP GET 요청은 Details 메서드에 맵핑됩니다. 이와 같은 형태의 라우팅은 ASP.NET MVC의 기본 라우팅과 매우 유사하며, RPC 스타일의 API에 보다 적합할 것입니다.

또한, ActionName 어트리뷰트를 사용하면 액션의 이름을 재정의 할 수도 있습니다. 가령, 다음 예제는 "api/products/thumbnail/id와 맵핑되는 두 개의 액션을 보여주고 있습니다. 한 메서드는 HTTP GET 메서드를 지원하고 또 다른 메서드는 HTTP POST 메서드를 지원합니다:

public class ProductsController : ApiController
{
    [HttpGet]
    [ActionName("Thumbnail")]
    public HttpResponseMessage GetThumbnailImage(int id);

    [HttpPost]
    [ActionName("Thumbnail")]
    public void AddThumbnailImage(int id);
}

비-액션 (Non-Actions)

메서드가 액션으로 노출되는 것을 막고 싶다면 NonAction 어트리뷰트를 사용하면 됩니다. 그러면, 프레임워크는 라우팅 규칙과 일치하는 경우에도 해당 메서드를 액션이 아니라고 인식합니다.

// 액션 메서드가 아님.
[NonAction]
public string GetPrivateData() { ... }

참고 목록

본 자습서에서는 라우팅에 대한 기초적인 내용들을 살펴봤습니다. 라우팅에 대한 보다 자세한 정보는, Web API 프레임워크가 URI와 라우트를 매치하고, 컨트롤러를 선택하고, 호출할 액션을 선택하는 방법을 상세하게 다루고 있는 Routing and Action Selection 문서를 참고하시기 바랍니다.