카테고리 없음

웹 API 설계: 놓치기 쉬운 핵심 - 표현 설계

씨씨상 2024. 10. 22. 19:48

 

 

표현 설계

 

 

많은 API 설계 논의는 URL 설계에 대한 광범위한 논의로 시작됩니다. 하지만 REST와 같은 데이터 지향 모델에서는 표현 설계부터 시작하는 것이 더 낫다고 생각합니다. URL 설계는 "URL 설계" 섹션에서 다룹니다. 표현(Representation)은 클라이언트가 서버에서 웹 자원을 가져오거나 클라이언트에서 서버로 보낼 때 반환되는 데이터에 대한 기술적인 용어입니다. REST 모델에서는 웹 자원이 내부 상태를 가지고 있으며, 이 상태는 직접 볼 수 없고 클라이언트와 서버 간에 주고받는 것은 그 상태의 표현입니다. 사용자는 자원의 표현을 미디어 타입(media types)이라고 불리는 다양한 형식으로 볼 수 있습니다. 원칙적으로, 특정 자원의 모든 미디어 타입은 동일한 정보를 단지 다른 형식으로 인코딩해야 합니다.

JSON 사용
웹 API에서 자원 표현의 주요 미디어 타입은 JavaScript Object Notation(JSON)입니다. JSON이 성공한 주된 이유는 아마도 그것이 이해하기 쉽고, JavaScript를 비롯한 다른 인기 프로그래밍 언어들(Python, Ruby, Java 등)의 데이터 구조로 쉽게 매핑할 수 있기 때문일 것입니다. 이제 JSON은 웹 API의 사실상 표준이 되었으며, 이를 사용해야 합니다.

JSON은 매우 좋고 인기가 많지만, 우리의 목적에 완벽하지는 않습니다. JSON의 한 가지 제한은 소수의 데이터 타입(Null, Boolean, Number, String)만을 표현할 수 있다는 것입니다. 웹 API 설계에서 자주 마주치는 데이터 타입 중 JSON이 지원하지 않는 것들은 날짜와 시간, 그리고 URL입니다. 이 제한을 처리하는 몇 가지 방법이 있는데, 가장 간단한 방법은 이를 문자열로 표현하고, 맥락을 통해 어떤 문자열이 단순한 문자열인지, 아니면 날짜나 URL로 변환된 문자열인지를 파악하는 것입니다. 이 책에서 이러한 옵션들에 대해 더 자세히 다룰 것입니다.

JSON을 간단하게 유지하기
JSON을 잘 사용하면 단순하고 직관적이며, 대부분의 경우 스스로 설명이 가능합니다. 만약 여러분의 JSON이 아래 예시처럼 명확해 보이지 않는다면, 뭔가 잘못된 것일 수 있습니다.

 

{
  "kind": "Dog",
  "name": "Lassie",
  "furColor": "brown",
};

 

JSON 사양에서는 JSON 객체가 이름/값 쌍의 모음이라고만 명시되어 있으며, 이름이 문자열로 제한된 것 외에는 이름이 무엇인지에 대해 설명하지 않습니다. 이 예시에서 이름은 표현이 JSON 객체로 감싸진 웹 자원의 속성에 해당합니다. 이러한 속성 이름은 때때로 문법 이론에서 차용한 용어인 술어(predicates)라고 불립니다. 여러분의 JSON이 더 간단하고 이해하기 쉬워지려면, JSON에서의 이름이 항상 속성 이름이어야 하며, JSON 객체는 항상 API의 데이터 모델 내의 엔티티에 대응하도록 하는 원칙을 따르는 것이 좋습니다.

다음은 Facebook Graph API의 예시로, JSON이 이 조언을 따르지 않았을 때 어떻게 보이는지 보여줍니다.

 

{
  "{user-id-a}": {
    data: [
      {
        id: "12345",
        picture: "{photo-url}",
        created_time: "2014-07-15T15:11:25+0000",
      },
      ... // More photos
    ],
  },
  "{user-id-b}": {
    data: [
      {
      ...
      }
    ],
  },
};

 

여기서 사용자의 ID가 다른 JSON 예시들에서 속성 이름이 있던 자리, 즉 콜론 왼쪽에 나타나는 것을 볼 수 있습니다. 또한, 이 JSON의 이름 데이터는 데이터 모델의 속성 이름과 일치하지 않으며, 이는 JSON 설계의 산물입니다. 우리는 이러한 JSON이 처음 예시에서 보여준 단순한 JSON이나 나중에 Google 및 GitHub의 예시보다 배우고 이해하기 더 어렵다고 생각합니다. 따라서 단순한 방식에 충실할 것을 권장합니다.

 

링크 포함하기
대부분의 문제 도메인에는 단순한 속성 외에도 개념적인 관계가 포함되어 있습니다. HTTP에서 이러한 관계를 나타내는 자연스러운 구조는 링크입니다.


몇 년 전만 해도, API에서 링크 사용은 클라이언트가 웹 브라우저처럼 동작할 수 있고, 그래야 한다는 아이디어와 강하게 연관되었습니다. 이는 클라이언트가 특정 API의 데이터나 의미를 미리 이해하지 않고, 서버가 반환하는 데이터의 내용, 특히 링크에 의해 클라이언트의 동작이 전적으로 결정된다는 의미입니다. 이 개념은 때때로 HATEOAS(Hypermedia As The Engine Of Application State, 하이퍼미디어가 애플리케이션 상태의 엔진이라는 뜻)라고 불립니다. 웹 브라우저가 이렇게 작동하는 것은 합리적입니다. 왜냐하면 웹의 각 사이트에 맞춘 커스텀 브라우저를 작성하는 것은 비현실적이기 때문입니다. 이러한 방식으로 작동하는 클라이언트는 특정 API에 대한 사전 지식을 가진 클라이언트보다 훨씬 더 복잡하고 비용이 많이 듭니다. 게다가 이러한 일반적인 API 클라이언트를 만드는 데 비용이 더 많이 들 뿐만 아니라, 일반적으로 사용자 인터페이스를 가진 클라이언트는 만족스럽지 않기 때문에 이러한 유형의 API 클라이언트는 거의 만들어지지 않으며, 대부분의 사람들은 이 접근 방식을 비실용적이라고 여깁니다.
하지만 최근 몇 년간의 변화는, 링크 사용이 완전히 범용적인 클라이언트를 대상으로 설계된 API뿐만 아니라, 모든 API의 사용성과 학습 가능성을 크게 개선한다는 사실을 깨닫게 되었다는 것입니다.

머리말에서 소개한 예시를 다시 살펴보면, 개와 주인 사이에 관계가 있다고 가정해봅시다. JSON에서 관계 정보를 나타내는 일반적인 방법은 다음과 같습니다:

 

{
  "id": "12345678",
  "name": "Lassie",
  "furColor": "brown",
  "ownerID": "98765432"
}

 

ownerID 필드는 관계를 표현합니다. 관계를 표현하는 더 좋은 방법은 링크를 사용하는 것입니다. 현재 웹 API에 링크가 포함되어 있지 않다면, 첫 번째 단계는 다른 변경을 하지 않고도 일부 링크를 추가하는 것입니다. 다음과 같이 말이죠:

 

{
  "id": "12345678",
  "name": "Lassie",
  "furColor": "brown",
  "ownerID": "https://dogtracker.com/persons/98765432"
}

 

주인의 표현이 이전에 다음과 같았다면:

 

{
  "id": "98765432",
  "kind": "Person",
  "name": "Joe Carraclough",
  "hairColor": "brown"
}

 

다음과 같이 개선할 수 있습니다:

 

{
  "id": "98765432",
  "kind": "Person",
  "name": "Joe Carraclough",
  "hairColor": "brown",
  "dogsLink": "https://dogtracker.com/persons/98765432/dogs"
}

 

왜 이 방식이 더 좋은가?
원래 예제에서는 Lassie의 표현이 있고, Lassie의 주인인 Joe의 표현을 얻고 싶다면, 적절한 URI 템플릿을 찾아 URL을 구성하기 위해 API 문서를 찾아야 했습니다. Lassie의 표현에는 ownerID가 있고, ownerID를 변수로 사용하여 주인을 찾는 URL 템플릿을 찾고 있었습니다. 이 접근법에는 여러 가지 단점이 있습니다. 하나는 데이터를 보는 대신 문서에서 찾는 것을 요구한다는 점입니다. 또 다른 단점은 표현에서 발견된 어떤 속성 값이 어떤 템플릿에 연결될 수 있는지를 설명하는 좋은 문서 규칙이 없기 때문에, 올바른 문서가 있더라도 일부 추측이 필요하다는 점입니다. 이 예제에서는 주인은 사람이라는 것을 알고, 사람의 ID를 변수로 사용하는 템플릿을 찾아야 했습니다. 세 번째 단점은 ownerID 속성 값을 템플릿과 결합하여 URL을 생성하는 코드를 작성해야 한다는 것입니다. URI 템플릿 사양에서는 이러한 코드를 템플릿 프로세서라고 합니다. 간단한 템플릿의 경우 이 코드는 꽤 사소하지만, 여전히 작성하고 디버깅해야 합니다.

 

반면 수정된 설계에서는 배울 것이 적고 API 사용이 더 쉽습니다. Joe의 URL이 데이터에 바로 나타나므로 문서에서 아무것도 찾을 필요가 없습니다. 클라이언트 코드를 작성하기도 더 쉬워집니다. ownerLink의 값을 가져와 HTTP 요청에서 사용하는 것만으로도 충분합니다. 템플릿과 변수 값을 조합하여 URL을 구성하는 코드를 작성할 필요가 없으며, API에 대한 내장 지식 없이도 이러한 링크를 따르는 범용 코드를 작성하고 사용할 수 있습니다. owner 리소스에 dogsLink를 추가하면 더 많은 가치를 제공합니다. dogsLink가 없다면, 데이터에서 소유자에서 개로 이동할 수 있는지조차 명확하지 않습니다. 웹의 주요 회사에서 제공하는 API의 수가 증가함에 따라 데이터에 링크를 포함하고 있습니다. '누가 링크를 사용하나요?' 섹션에서 Google과 GitHub의 몇 가지 예를 공유할 것입니다.

링크가 있으면 URI 템플릿이 여전히 필요한가?
네, 여전히 중요합니다. 링크는 현재 위치에서 갈 수 있는 곳을 표현합니다. 링크는 시스템을 가로지르는 포장된 경로에 대한 이정표입니다. URI 템플릿은 단축키와 같아서, 매우 구체적인 목적지가 있을 때 잔디밭을 가로지르는 방법입니다. 링크가 있는 API에서는 이미 가지고 있는 리소스의 표현에 유용한 링크가 있어 원하는 곳으로 이동하는 경우가 종종 발생합니다. 그러나 링크가 없거나 링크를 따라 이동하는 경로가 지나치게 길 경우도 발생합니다. 그럴 때는 필요한 리소스를 찾기 위한 다른 방법이 필요합니다. URI 템플릿이 이를 제공하는 방법입니다.

URI 템플릿은 변수 값이 사람에게 읽고 기억하기 쉬운 경우 가장 유용합니다. 예를 들어, 다음 URL 템플릿은 약간의 유용성이 있지만,

 

https://dogtracker.com/persons/{personID}

 

personID가 어떤 불명확하고 긴 식별자인 경우에는 전체 URL을 기억하는 것만큼이나 어렵습니다. 반면, 다음 템플릿은 사람들이 세상과 상호작용하는 방식을 매우 기본적으로 다루기 때문에 더 유용합니다. 

 

https://dogtracker.com/persons/{personName}

 

이는 도메인 이름이 이름을 IP 주소에 매핑하기 위해 존재하는 이유와 같습니다. 예를 들어, Google Cloud 블로그를 운영하는 서버에 링크를 따라가면 도메인 이름이나 IP 주소가 포함되어 있는지에 대해 신경 쓰지 않고 사용합니다. 도메인 이름 blog.apgiee.com을 사용하는 것은 URL을 입력할 때 경험을 향상시킵니다.

 

월드 와이드 웹과의 유사성
HTML 웹은 HTML 링크로 연결된 문서의 네트워크입니다. 웹을 탐색하는 기본적인 방법은 리소스 간에 링크를 따라 이동하는 것입니다. URL을 직접 입력하거나 즐겨찾기에서 접근할 수도 있지만, 아는 URL의 수에는 한계가 있습니다. 웹 초기에 링크를 따르거나 URL을 입력하는 것이 유일한 탐색 방법이었습니다. 일부 회사(가장 유명한 것은 Yahoo!)는 리소스 발견 문제를 해결하기 위해 링크 탐색 메커니즘을 확장했습니다. 아이디어는 https://yahoo.com이 웹의 단일 루트가 되어, 거기에서 Yahoo 카테고리의 링크를 통해 필요한 곳으로 이동할 수 있다는 것이었습니다. 다른 회사(가장 유명한 것은 Google)는 페이지에서 알고 있는 정보를 사용하여 웹 페이지 검색을 수행할 수 있게 해주었습니다(페이지의 텍스트에 나타나는 키워드나 문자열). 해당 페이지를 발견한 후, 포함된 링크를 클릭하여 새로운 페이지로 이동할 수 있으며, 유용한 링크가 더 이상 없을 때까지 진행할 수 있습니다. 이제 모든 사람은 웹을 사용하는 방식이 검색과 링크 탐색의 조합이라는 사실을 당연하게 여기고 있습니다.

전형적인 웹 API의 URI 템플릿을 이해하는 한 가지 방법은 이를 Google 검색에 비유하는 것입니다. URI 템플릿은 URL을 모르는 리소스를 찾는 데 도움이 되며, 해당 리소스에서 알고 있는 정보의 일부를 사용할 수 있습니다. 대부분의 사람들은 웹 브라우저를 통해 다음과 같은 URL로 Google 검색을 수행하는 방법을 알고 있습니다:

 

https://www.google.com/search?q=web+api+design


웹 API 설계자는 다음과 같은 URL 템플릿을 정의할 때

 

https://dogtracker.com/persons/{personId}/dogs

 

사실상 그들의 애플리케이션을 위한 특수한 쿼리 언어를 정의하고 있는 것입니다. 동일한 쿼리는 다음과 같이 표현될 수 있습니다:

 

https://dogtracker.com/search?type=Dog&ownerId={personId}



Google은 모든 웹사이트에서 보편적인 검색 언어를 제공하는 반면, URI 템플릿은 특정 리소스 집합(즉, API)에 고유한 쿼리 언어를 정의합니다. API에 고유한 쿼리 언어를 설계하는 것은 데이터 및 사용 사례에 대한 지식을 사용하여 리소스를 위한 보다 사용 가능하고 이해하기 쉬운 쿼리 기능을 정의하고 구현 비용을 제한하는 데 도움이 될 수 있습니다. 단점은 각 API의 쿼리 언어를 개별적으로 배워야 한다는 것입니다. 모든 API에서 지원되는 보편적인 쿼리 언어가 있다면, 모든 API 클라이언트 애플리케이션 개발자의 생산성이 향상될 것입니다. 우리는 '쿼리 URL 설계'라는 섹션에서 쿼리 URL을 규칙적이고 예측 가능하게 만드는 방법을 살펴보겠습니다.

많은 사람들은 쿼리를 통해 리소스를 찾기 위한 URI 템플릿의 성공에 만족하며, 다른 메커니즘인 링크의 가치를 무시해왔습니다. 반대 극단에서는 일부 링크 지지자들이 쿼리/검색 없이 단일 루트 모델을 주장하였습니다. 이 두 기술은 HTML 웹과 마찬가지로 웹 API에도 서로 귀중한 보완 요소입니다.

 

링크 포함하기, 2단계
위와 같이 URL 값을 가진 속성만 추가해도 API를 크게 개선하게 됩니다. URL 값을 가진 속성을 읽기 전용으로 설정하고, 현재 방식을 계속 사용하여 업데이트를 진행할 수 있습니다. 예를 들어, Lassie의 주인을 Duke of Rudling으로 변경하고 싶다면, PUT 또는 PATCH 요청을 통해 ownerID의 값을 Duke의 ID로 변경하고, ownerLink 속성은 서버에 의해 재계산될 것입니다. 기존 API를 발전시키고 있다면, 이는 매우 실용적인 단계입니다. 그러나 새 API를 설계하고 있다면, 링크로 한 걸음 더 나아가고 싶을 것입니다.

다음 예를 고려해 보십시오. 개는 사람이나 기관(예: 회사, 교회, 정부, 자선단체 및 NGO)에 의해 소유될 수 있다고 가정합니다. 우리의 개 추적 사이트는 경찰 개 및 개인에 속하지 않는 기타 작업 개의 소유를 추적할 수 있도록 이 모델을 허용하려고 합니다. 또한 기관은 개와 다른 테이블(또는 데이터베이스)에 저장되며, 고유한 ID 집합을 가집니다. 이 시점에서 단순한 값을 가진 ownerID 속성만으로는 소유자를 참조하는 것이 충분하지 않으므로, 서버가 어떤 테이블(또는 데이터베이스)에서 찾아야 하는지를 알 수 있도록 소유자 유형을 명시해야 합니다. 여러 가지 해결책이 가능합니다: ownerIDownerType 속성을 가질 수 있으며, 또는 personOwnerIDinstitutionalOwnerID 속성을 가질 수 있습니다. 이 중 한 가지만 설정할 수 있습니다. 두 가지를 모두 인코딩한 복합 소유자 값을 발명할 수도 있습니다. 각 해결책마다 장단점이 있지만, 매우 우아하고 유연한 옵션은 링크를 사용하여 문제를 해결하는 것입니다. 예제를 다음과 같이 수정해보면 다음과 같습니다:

 

{
  "self": "https://dogtracker.com/dogs/12345678",
  "id": "12345678",
  "kind": "Dog"
  "name": "Lassie",
  "furColor": "brown",
  "owner": "https://dogtracker.com/persons/98765432"
}

 

명시적인 변화는 ownerID 속성이 제거되었고, 이제 URL 값이 있는 단일 owner 필드가 있다는 점입니다. 암시적인 변화는 URL 값이 있는 owner 속성이 이제 읽기 전용이 아닌 읽기-쓰기 속성으로 변경되었다는 것입니다. 이제 사람의 URL이든 기관의 URL이든 그 값을 설정함으로써 사람과 기관의 소유자를 모두 쉽게 처리할 수 있습니다. 클라이언트는 owner URL이 다양한 리소스를 가리킬 수 있다는 것을 인지해야 하며, 이 링크를 탐색할 때 반환되는 데이터에 따라 다르게 반응할 준비가 되어 있어야 합니다. 이는 웹 브라우저의 동작 방식과 정확히 동일합니다. 브라우저는 웹 페이지의 링크를 따라가며, 그 끝에서 HTML 페이지, XML, PDF, JPEG 등 다양한 형식의 데이터를 발견하고 이에 맞게 적절히 작동합니다. 이러한 모델은 강력하고 유연하며, 많은 클라이언트가 익숙하지 않을 수 있는 몇 가지 요구사항을 제시하지만, 저희가 추천하는 모델입니다.

 

주의 사항
저희는 읽기-쓰기 URL 값 속성 모델을 매우 좋아하지만, 이 모델은 서버 구현자들에게 몇 가지 영향을 미칩니다. 일반적으로 도메인 이름이 포함된 전체 URL을 데이터베이스에 저장하는 것은 좋은 아이디어가 아닙니다. 시스템의 도메인 이름이 변경되면 데이터베이스에 저장된 모든 URL이 잘못되기 때문입니다. 운영 서버의 도메인 이름 변경은 바람직하지 않지만, 때로는 피할 수 없을 때도 있습니다. 운영 서버의 이름 변경을 피할 수 있다 하더라도, 다른 환경(예: 통합 테스트, 시스템 테스트, 사전 운영)에서 동일한 데이터베이스를 다른 도메인 이름 또는 IP 주소로 사용하는 자유를 누리고 싶을 것입니다. 이를 위해 서버는 자체 리소스를 식별하는 URL에서 스키마와 권한(도메인 이름 부분)을 제거한 후에 데이터베이스에 저장하고, 요청 시 이를 다시 추가해야 합니다. API 외부의 리소스를 식별하는 URL은 아마도 절대 URL로 저장해야 할 것입니다. 절대 URL을 데이터베이스에 저장하는 것에 익숙하지 않다면, 그렇게 하지 않는 것이 좋습니다.

절대 URL을 데이터베이스에 저장하는 문제를 피하는 방법 중 하나는 API에서 상대 URL을 수락하고 생성하는 것입니다. 특히 사양에서 'path-absolute'라고 불리는, 단일 /로 시작하는 URL이 유용합니다. 이는 합리적인 접근 방식이며, 서버에서 여러 구현 문제를 피할 수 있습니다. 단, 이는 클라이언트에 부담을 줄 수 있는데, 클라이언트는 이 상대 URL을 사용하기 전에 절대 URL로 변환해야 하기 때문입니다. 클라이언트에게 좋은 소식은 상대 URL을 절대 URL로 변환하는 것은 URL 표준에 대한 일반적인 지식만으로도 가능하다는 점입니다. API에 대한 특정한 지식은 필요하지 않습니다. 나쁜 소식은 경우에 따라 클라이언트가 URL이 상대적인 기준(base)을 설정하는 것이 까다로울 수 있다는 점입니다. 서버에서 절대 URL을 생성하고 사용하는 방법을 배울 의지가 있다면, 사용자에게 더 나은 API를 제공할 수 있을 것입니다.

일반적으로 리소스 표현에서 URL을 처리하는 서버를 작성하는 것은 배워야 할 기술입니다. 읽기 전용의 상대 URL을 추가하는 것은 비교적 쉬운 작업이며, 그 정도의 목표라면 그대로 진행할 수 있을 것입니다. 절대 URL을 제공하고, 읽기-쓰기 URL 값 속성을 처리하는 것은 서버에 몇 가지 설계 및 구현 문제를 추가합니다. 다행히도 이러한 문제의 해결책은 매우 어렵지 않지만, 첫 시도에서 잘못 처리하기 쉽습니다.

 

리소스에서 링크를 어떻게 표현해야 하는가?
저희가 선호하는 링크 표현 방식은 간단한 JSON 이름/값 쌍을 사용하는 것입니다. 다음과 같은 방식입니다:

 

"owner": "https://dogtracker.com/persons/98765432"

 

이 접근 방식의 장점은 무엇인가요? 이 방식은 매우 간단하며, JSON에서 단순 속성을 표현하는 방식과 일관됩니다. 단점은 JSON이 URL 값을 위한 별도의 인코딩을 제공하지 않으므로, URL을 문자열로 인코딩해야 한다는 점입니다. 클라이언트가 메타데이터를 갖고 있지 않다면, 어떤 문자열이 실제 URL인지를 추측해야 하며, 이를 위해 모든 문자열 값을 파싱하거나 상황에 따른 정보를 활용해야 할 수 있습니다. 하지만 보통 클라이언트 측에서 작성된 맞춤형 코드의 경우, 문서를 확인하고 어떤 속성이 URL 값인지 미리 알고 작성하기 때문에 큰 문제가 되지 않습니다. 문제는 API의 세부 사항을 알지 못한 채, 어떤 API에서든 표현을 처리할 수 있는 범용 클라이언트나 라이브러리 코드를 작성할 때 발생합니다.

링크를 표현하기 위한 더 복잡한 패턴이 상당수 존재하며, 부록에서 이에 대한 추가 정보를 포함하고 있습니다. 이러한 패턴을 사용하든 말든, 링크를 사용하는 데 있어 단순한 JSON 속성 이상의 복잡한 구조가 반드시 필요한 것은 아니라고 생각합니다. 저희는 여러 스타일을 사용해 프로젝트를 진행해 본 경험이 있지만, 현재로서는 가능한 한 간단하게 유지하는 것을 선호합니다.

 

누가 링크를 사용하는가?

API에 링크를 포함하라는 위의 권장 사항은 공개된 API에서 가장 일반적인 관행은 아니지만, Google Drive API나 GitHub와 같은 매우 잘 알려진 API에서 사용되고 있습니다. 아래는 Google Drive API와 GitHub의 예시입니다. Google Drive의 문제 영역이 이러한 기술에 특히 적합하다고 생각할 수 있지만, 우리는 이러한 기술이 다양한 문제 영역에도 동일하게 적용될 수 있다고 믿으며, 우리 역시 많은 디자인에서 이를 사용해 왔습니다.

다음은 Google Drive API의 예시입니다:

 

GET
https://www.googleapis.com/drive/v2/files/0B8G-Akr_SmtmaEJneEZLYjB
HTTP/1.1 200 OK
…
{
  "ind": "drive#file",
  "id": "0B8G-Akr_SmtmaEJneEZLYjBBdWxxxxxxxxxxxxxxxx",
  "etag": "\"btSRMRFBFi3NMGgScYWZpc9YNCI/MTQzNjU2NDk3OTU3Nw\"",
  "selfLink": "https://www.googleapis.com/drive/v2/files/0B8G-Akr_Smtm",
  "webContentLink": "https://docs.google.com/uc?id=0B8G-Akr_SmtmaEJneE",
  "alternateLink": "https://drive.google.com/file/d/0B8G-Akr_SmtmaEJne",
  "iconLink": "https://ssl.gstatic.com/docs/doclist/images/icon_12_pdf",
  "thumbnailLink": "https://lh4.googleusercontent.com/REcVMLRuNGsohM1C",
  "title": "Soils Report.pdf",
  "mimeType": "application/pdf",
  …
  "parents": [
    {
      "kind": "drive#parentReference",
      "id": "0AMG-Akr_SmtmUk9PVA",
      "selfLink": "https://www.googleapis.com/drive/v2/files/0B8G-Akr_Sm",
      "parentLink": "https://www.googleapis.com/drive/v2/files/0AMG-Akr_",
      "isRoot": false
    }
  ],
  …

 

예시 코드가 너무 길어져 일부 내용이 잘린 상태로 표시된다는 점을 주의하세요.

다음은 GitHub API에서 가져온 또 다른 예시입니다:

 

{
  "id": 1,
  "url": "https://api.github.com/repos/octocat/Hello-World/issues/1347",
  "repository_url": "https://api.github.com/repos/octocat/Hello-World",
  "Labels_url":"https://api.github.com/repos/octocat/Hello-World/is sues/1347/labels{/name}",
  "comments_url": "https://api.github.com/repos/octocat/Hello-World/issues/1347/comments",
  "events_url": "https://api.github.com/repos/octocat/Hello-World/issues/1347/events",
  "html_url": "https://github.com/octocat/Hello-World/issues/1347",
  "number": 1347,
  "state": "open",
  "title": "Found a bug",
  "body": "I’m having a problem with this.",
  "user": {
  "login": "octocat",
  "id": 1,
  "avatar_url": "https://github.com/images/error/octocat_happy.gif",
  "gravatar_id": "",
  "url": "https://api.github.com/users/octocat",
  "html_url": "https://github.com/octocat",
  "followers_url": "https://api.github.com/users/octocat/followers",
  "following_url": "https://api.github.com/users/octocat/following{/other_user}",
  "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
  "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
  "subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
  "organizations_url": "https://api.github.com/users/octocat/orgs",
  "repos_url": "https://api.github.com/users/octocat/repos",
  "events_url": "https://api.github.com/users/octocat/events{/privacy}",
  "received_events_url": "https://api.github.com/users/octocat/received_events",
  "type": "User", "site_admin": false
},
"labels": [
  {
    "url": "https://api.github.com/repos/octocat/Hello-World/labels/bug",
    "name": "bug",
    "color": "f29513"
  }
],
…

 

GitHub의 값들이 모두 단순한 URL이 아니라 일부는 URI 템플릿이라는 것을 알 수 있을 것입니다. 템플릿은 하나의 문자열로 여러 리소스의 URL을 전달할 수 있게 해주지만, 그 대신 클라이언트가 템플릿을 처리해야 하는 부담이 있습니다.

 

더 많은 내용

나중에 표현 설계에 대해 더 할 말이 있으며, "표현 설계에 대한 추가 내용"이라는 섹션에서 이 주제로 돌아올 것입니다. 이제 URL 설계에 대해 다루도록 하겠습니다.

 

 

 

 

 

[출처]

APIGEE-WEB-API-DESIGN-THE-MISSING-LINK