[번역] REST 리소스 네이밍 가이드
이 글은 REST API Tutorial의 REST Resource Naming Guide 글을 번역해 작성한 글입니다.
최대한 원본 내용을 유지하겠으나, 중간에 제가 읽었을 때 모르는 것 또는 이해가 안 되는 부분은 파란색 글씨로 적어두니 참고 바랍니다.
REST 리소스 네이밍 가이드
여기서 REST란, 웹에 존재하는 모든 자원(이미지, 동영상 등)에 고유한 URI를 부여해 활용하는 방법론을 의미합니다.
REST 상에서, 주요 데이터들은 리소스(자원)이라 부른다.
강력하고 일관된 REST 리소스 네이밍 전략을 사용하는 것은 장기적으로 봤을 때 가장 좋은 선택 중 하나가 될 것이다.
리소스는 싱글톤 또는 컬렉션이 될 수 있다.
예를 들어, customers는 컬렉션 리소스이고, customer는 싱글톤 리소스이다. (은행 도메인에서)
우리는 /customers 라는 URI를 사용해서 customers 컬렉션을 식별할 수 있고
/customers/{customerId} URI를 사용해서 단일의 customer 리소스를 식별할 수도 있다.
또한 리소스는 서브 컬렉션 리소스들을 포함할 수도 있다.
예를 들어, 서브 컬렉션 리소스인 customer의 accounts 는 /customers/{customerId}/accounts 라는 URN을 사용해 식별할 수 있다. 비슷하게 accounts 안에 있는 싱글톤 리소스 account 도 포함해 식별할 수 있는데,
이 때는 /customers/{customerId}/accounts/{accountId} 가 된다.
REST API는 Uniform Resource Identifiers (URIs)를 사용하여 리소스를 처리한다.
따라서 REST API 디자이너들은 REST API의 리소스 모델을 잠재적인 클라이언트 개발자들에게 보내기 위한 URI를 만들어야 한다. 만약 리소스의 이름이 잘 지정되면, API는 직관적이고 사용하기 쉽다. 그러나 제대로 지정되지 않았다면, 동일한 API라고 해도 어렵고 이해 안 되게 느껴질 수 있다.
아래에서는 여러분들이 새로운 API를 위해 URIs를 만들 때 도움이 될 몇 가지 방법들을 소개한다.
REST Resource Naming Best Practices
명사들을 사용해 리소스를 만들 것
RESTful URI는 동사 대신 명사를 사용해 리소스를 나타내야 한다. 이는 동사엔 없는 명사의 성질 때문인데, 이 성질은 리소스의 성질과도 유사하다. 다음 리소스의 몇 가지 예시를 살펴보자.
- 시스템의 유저들
- 유저의 계좌들
- 네트워크 장비들
그리고 이에 해당하는 리소스 URI는 이렇게 디자인될 수 있다.
http://api.example.com/device-management/managed-devices
http://api.example.com/device-management/managed-devices/{device-id}
http://api.example.com/user-management/users/
http://api.example.com/user-management/users/{id}
더 명확히 하기 위해, 리소스의 원형을 4가지 범주(문서, 컬렉션, 스토어, 컨트롤러)로 나눈 다음 항상 그중 하나로 지정하여 네이밍을 일관적으로 사용하는 것을 목표로 해야 한다. 균일성을 위해 두 가지 이상을 혼합하고 싶은 유혹을 물리쳐야 한다.
1. 문서 리소스 (document)
문서 리소스는 객체 인스턴스 또는 데이터베이스 레코드와 유사한 단일 개념이다.
REST에서는 컬렉션 안에 있는 하나의 리소스에 해당하는데, 문서 리소스의 상태를 표현할 때는 일반적으로 값이 있는 필드와 다른 연관된 리소스들에 대한 링크를 모두 포함한다.
문서 리소스를 사용할 때는 "단수"를 사용해야 한다.
(예시)
http://api.example.com/device-management/managed-devices/{device-id}
http://api.example.com/user-management/users/{id}
http://api.example.com/user-management/users/admin
2. 컬렉션 리소스 (collection)
컬렉션 리소스는 리소스의 서버 관리 디렉터리이다. 클라이언트는 컬렉션에 추가할 새로운 리소스를 제안할 수 있지만 새로운 리소스를 만들지 여부를 선택하는 것은 컬렉션에 달려있다. 컬렉션 리소스는 포함하려는 항목을 선택하고, 포함된 각 리소스의 URI도 결정한다.
컬렉션 리소스를 사용할 때는 "복수"를 사용해야 한다.
http://api.example.com/device-management/managed-devices
http://api.example.com/user-management/users
http://api.example.com/user-management/users/{id}/accounts
3. 스토어 리소스
스토어는 클라이언트 관리 리소스 저장소이다.
스토어 리소스를 사용하면 API 클라이언트가 리소스를 넣고, 꺼내고, 삭제할 시기를 결정할 수 있다.
또한 스토어는 새로운 URI를 생성하지 않고, 대신 각각의 스토어 리소스에 URI가 있다. 이런 URI는 최초로 스토어에 넣을 때 클라이언트가 선택을 한다.
스토어 리소스를 사용할 때는 "복수"를 사용해야 한다.
http://api.example.com/song-management/users/{id}/playlists
4. 컨트롤러 리소스
컨트롤러 리소스는 절차적 개념을 모델링한다. 컨트롤러 리소스는 함수처럼 파라미터, 리턴 값이 있다.
컨트롤러 리소스를 사용할 때는 "동사"를 사용해야 한다.
http://api.example.com/cart-management/users/{id}/cart/checkout
http://api.example.com/song-management/users/{id}/playlist/play
일관성이 핵심이다
모호함을 최소화하고 가독성과 유지보수성을 최대화하기 위해 일관된 리소스 네이밍 규칙은 필수적이다.
일관성을 유지하기 위한 방법들은 아래와 같다.
1. 계층 관계를 나타낼 때는 슬래시(/)를 사용하자.
슬래시는 리소스들 간의 계층적 관계를 나타내기 위해 URI 경로 부분에 사용된다.
http://api.example.com/device-management
http://api.example.com/device-management/managed-devices
http://api.example.com/device-management/managed-devices/{id}
http://api.example.com/device-management/managed-devices/{id}/scripts
http://api.example.com/device-management/managed-devices/{id}/scripts/{id}
2. URI 마지막 부분에 슬래시(/)를 사용하지 말자.
마지막 부분의 슬래시는 의미가 있는 문자가 아니기 때문에 다른 개발자들에게 혼동을 일으킬 수도 있다.
따라서 완전히 버리는 것이 좋다.
http://api.example.com/device-management/managed-devices/
http://api.example.com/device-management/managed-devices /*This is much better version*/
3. URI의 가독성을 높이기 위해 hyphens(-)을 사용하자.
긴 경로로 이루어진 경우 hyphen 문자들을 사용하면 가독성을 향상할 수 있다.
http://api.example.com/inventory-management/managed-entities/{id}/install-script-location //More readable
http://api.example.com/inventory-management/managedEntities/{id}/installScriptLocation //Less readable
4. 언더스코어( _ )를 사용하지 말자.
일부 브라우저나 화면에서 언더스코어는 부분적으로 가려지거나, 완전히 숨겨질 수 있다. 이러한 혼동을 방지하기 위해 hyphen을 대신 사용하자.
http://api.example.com/inventory-management/managed-entities/{id}/install-script-location //More readable
http://api.example.com/inventory_management/managed_entities/{id}/install_script_location //More error prone
5. URI 주소엔 영어 소문자만 사용하자.
편리성을 위해 소문자만 일관되게 사용하는 것이 좋다.
RFC 3986에 따르면, 호스트 컴포넌트와 스키마를 제외하고는 영어 대소문자를 구분하는데, 다음 예시를 보자.
http://api.example.org/my-folder/my-doc //1
HTTP://API.EXAMPLE.ORG/my-folder/my-doc //2
http://api.example.org/My-Folder/my-doc //3
위 예시의 경우 1,2번은 같지만 3번은 My-Folder 부분이 컴포넌트, 스키마가 아니기 때문에 다르게 구분된다.
이런 사례를 사전에 막기 위해 모두 소문자로 구성하는 게 좋겠다.
6. 파일 확장자를 사용하지 말자.
파일 확장자는 보기에 좋지 않으며, 사용한다고 어떠한 장점도 없다. 차라리 URI의 길이를 줄이는 게 이득이다.
만약 파일 확장자를 강조하고 싶다면 대신 Content-Type 헤더를 통해 컨텐츠를 처리하는 방법을 결정하는 것이 좋다.
http://api.example.com/device-management/managed-devices.xml /*Do not use it*/
http://api.example.com/device-management/managed-devices /*This is correct URI*/
URI에 CRUD 함수 이름을 사용하지 말 것
CRUD 기능이 수행된 걸 표시하기 위한 매개체로 URI를 사용해서는 안 된다.URI는 리소스를 고유하게 식별하는 데 사용되어야 하지, 특정 리소스에 대한 조치를 표시하는 데 사용하면 안된다.대신 HTTP 요청 메서드가 CRUD 기능을 나타내는 데 사용해야 한다.
HTTP GET http://api.example.com/device-management/managed-devices //Get all devices
HTTP POST http://api.example.com/device-management/managed-devices //Create new Device
HTTP GET http://api.example.com/device-management/managed-devices/{id} //Get device for given Id
HTTP PUT http://api.example.com/device-management/managed-devices/{id} //Update device for given Id
HTTP DELETE http://api.example.com/device-management/managed-devices/{id} //Delete device for given Id
쿼리 파라미터, 쿼리 스트링을 사용해 URI 컬렉션을 필터링하라.
개발하다 보면, 하나의 컬렉션에 대해 특정 속성에 따라 정렬, 필터링, 제한하는 요구 사항을 접하게 된다.
이를 위해 새로운 API를 만드는 것보다, 리소스 컬렉션 API에서 해당 기능을 활성화한 후, 쿼리를 전달받아 처리하도록 하자.
http://api.example.com/device-management/managed-devices
http://api.example.com/device-management/managed-devices?region=USA
http://api.example.com/device-management/managed-devices?region=USA&brand=XYZ
http://api.example.com/device-management/managed-devices?region=USA&brand=XYZ&sort=installation-date
끝으로
아무개의 추천을 받아 처음 번역 글을 쓰게 되었는데, 생각보다 힘들고 내가 적지만 이해가 되지 않는 문장이 꽤 있다.아마 이러한 이유로 원서 읽는 습관을 들이라고 하는 것 같은데,, 피곤할 때 외국어 읽는 것만큼 힘든 게 없어서.. 쉽사리 도전하지 못하고 있다. (코드포스는 재미있다!)
API를 설계하는 강의를 듣다 보면, 강사분이 그냥 자연스럽게 URI를 위의 방식대로 쓰시는데, 막상 내가 하다 보면 계층 하나도 안 지키고 무지성으로 하고 있는 것 같다. 이렇게 번역까지 했으니 다음부턴 꼭 생각하면서 적어야겠다!