RESTful API 네이밍

명확하고 일관된 API 디자인을 위한 가이드

김경태
PentaSecurity Labs
10 min readMay 31, 2023

--

웹 서비스의 백앤드는 RESTful API를 제공하는 것이 기본이 되어 버린 지 오래다. REST API를 작성 할 때 직관적이고 일관성 있게 작성하기 위해 서는 네이밍 컨벤션이 필요 하다. 우리가 코딩 켄벤션을 사용 하는 것처럼 말이다. 이 문서는 개발자들이 REST API를 더 RESTful하고, 직관적이며 사용이 용이 하도록 설계하는데 도움이 되기를 바라며 작성 되었다. 이 문서는 이해 하는 데는 HTTP, Front-end, Back-end, URI 등의 사전 기본 지식을 필요로 한다.

우선 REST에 관해서 간략히 소개 한다. REST 는 Representational State Transfer 의 약어로, 하이퍼미디어를 전송하는 방법에 대한 구조적 규칙이다. 하이퍼미디어를 구성하는 모든 자원(resource)을 이름으로 구분하여 해당 자원의 정보를 주고 받는 방법에 대한 모든 것을 의미 한다. REST는 6가지의 원칙과 제약을 갖는다. RESTful 서비스 인터페이스는 이 6가지 원칙과 제약을 준수 해야 한다.

REST의 6가지 원칙과 제약

  1. 일관된 인터페이스(Uniform interface)
    URI로 지정한 자원(resource)에 대한 조작을 통일되고 한정적인 인터페이스로 수행하는 구조적 스타일을 말한다.
  2. 클라이언트 — 서버(Client — Server)
    자원를 제공하는 쪽이 서버, 자원을 요청 하는 쪽을 클라이언트라 한다. 이 둘은 독립적으로 분리되어 구성되어야 한다. 각각 별도로 개발되고 대체 가능하도록 유지 해야 한다.
  3. 무상태(Stateless)
    작업에 대한 요청의 상태 정보를 저장하거나 관리 하지 않는다. 세션, 인증, 쿠키 등의 정보는 별도로 저장하기 때문에 요청에 대한 어떠한 상태 정보를 저장하지 않고 단순 처리할 수 있어야 한다. 이를 위해 모든 요청에는 필요한 모든 정보가 포함되어야 한다.
  4. 캐시의 가능(Cacheable)
    서버는 캐시 가능 여부를 제공해야 한다. 캐시가 가능 할 경우 클라이언트는 응답 데이터를 재 사용 하여 성능과 서버의 가용성을 올릴 수 있다.
  5. 계층화된 시스템(Layered System)
    계층화된 구조로 구성되어야 한다. 각 계층 자신이 통신하는 컴포넌트 외 다른 계층에 대한 정보를 얻을 수 없도록 분리되어야 한다.
  6. 주문형 코드(선택사항)(Code on Demand)
    클라이언트는 서버로부터 실행시킬 수 있는 로직을 다운 받아 기능을 확장시킬 수 있다. 이를 통해 클라이언트가 사전에 구현해야 하는 기능의 수를 줄여 간소화 시킬 수 있다.

REST API는 URI(Uniform Resource Identifier)를 이용하여 자원(resource)을 가리키고, 자원에 접근 할 수 있도록 한다. REST API 설계자는 자원에 접근 할 수 있는 URI를 만들어 클라이언트에 제공 해야 한다. URI에서 자원을 구분 지어 명명하고, 일관된 형식을 사용하도록 한다. 이는 모호성을 최소화하고 가독성, 유지 관리성을 극대화할 수 있는 방법이며, 사용하기 직관적이고 쉬울 것이다. 이와 같이 URI를 만들기 위한 네이밍 규칙을 소개 한다.

자원을 명사로 나타내라

RESTful URI가 가리키는 자원은 객체이다. 때문에 동사가 아니라 명사로 칭한다. 자원은 4가지 범주로 분류 할 수 있다.(문서(Document), 컬렉션(Collection), 스토어(Store), 컨트롤(Controll)) 자원이 어떤 범주에 속하는지 에 따라 일관된 네이밍을 사용 한다.

  • 문서(Document)
    문서 자원은 DB의 하나의 레코드, 하나의 객체 인스턴스와 유사한 단일 자원의 개념이다. 단수를 사용 하여 문서 자원을 표현한다.
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
  • 컬렉션
    서버가 관리하는 리소스 디렉터리이다. 클라이언트에 의해 새로운 리소스 추가가 요청 될 수 있다.(POST사용) 복수를 사용 하여 컬렉션 자원을 표현한다.
http://api.example.com/device-management/managed-devices
http://api.example.com/user-management/users
http://api.example.com/user-management/users/{id}/accounts
  • 스토어
    스토어는 클라이언트가 관리 하는 자원 저장소이다. 클라이언트는 API를 이용하여 자원을 넣거나 가져올 수 있고 삭제 할 수 있다. 복수를 사용하여 스토어를 표현한다.
http://api.example.com/song-management/users/{id}/playlists
  • 컨트롤러
    컨트롤러 자원은 인자와 반환 값, 입력 및 출력이 있는 실행 가능한 함수와 같다. 문서, 컬렉션, 스토어로 해결이 어려운 절차적 실행을 수행하기 위한 모델이다. 특정 자원을 가리키는 것이 아니라 실행 인 만큼 예외적으로 동사를 사용한다.
http://api.example.com/cart-management/users/{id}/cart/checkout
http://api.example.com/song-management/users/{id}/playlist/play

계층 관계를 나타내기 위해 ‘/’ 를 사용한다.

자원 간의 계층 관계를 표현하기 위해 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}

URI의 마지막에 ‘/’를 사용 하지 않는다.

URI의 마지막에 ‘/’를 사용 할 경우 혼동을 줄 수 있으므로 사용하지 않는다.

http://api.example.com/device-management/managed-devices/ 
http://api.example.com/device-management/managed-devices
/*아래가 더 좋은 사용법이다.*/

‘-’(하이픈)을 사용하여 가독성을 높인다.

긴 경로 이름에 ‘-’(하이픈)을 사용 하면 가독성을 높일수 있으며, 사람들이 쉽게 인식하고 해석 할 수 있게 도움을 준다.

http://api.example.com/devicemanagement/manageddevices
http://api.example.com/device-management/managed-devices
/*아래가 더 좋은 사용법이다.*/

‘_’(언더스코어)는 사용하지 않는다.

어플리케이션의 폰트에 따라, 일부 브라우저에서 ‘-’(언더스코어)는 불명확하게 표현되거나 보이지 않을 수 있다.

http://api.example.com/inventory_management/managed_entities/{id}/install_script_location
//폰트에 따라 읽기 불편하고, 에러 발생의 여지가 있다.

http://api.example.com/inventory-management/managed-entities/{id}/install-script-location
//더 읽기 편하다.

소문자를 사용 한다.

URI에 일관되게 소문자를 사용하도록 한다.
Schem, HOST는 대소문가 구분이 없으나 이외에는 모두 대소문자가 구분된다. 아래 예시에서 1번과 2번은 동일 하지만 3번은 다르다.

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

파일의 확장자는 사용하지 않는다.

파일 확장자는 가독성을 해치고 어떤 이점도 존재 하지 않는다. 파일 확장자를 제거 하여 URI의 길이를 줄이는 것이 더 좋다.
만약 자원의 유형을 강조 해야 할 필요가 있다면 Content-Type 헤더를 이용하는 방법을 활용 할 수 있다.

http://api.example.com/device-management/managed-devices.xml
/*확장자를 사용하지 말아라*/

http://api.example.com/device-management/managed-devices
/*올바른 URI*/

CRUD함수 명을 사용하지 않는다.

URI는 자원을 가리키는 것이다. 어떤 동작을 가리켜서는 안된다. CRUD는 HTTP의 요청 메소드를 이용하여 표현 할 수 있다.

HTTP GET http://api.example.com/device-management/managed-devices  //모든 디바이스를 요청
HTTP POST http://api.example.com/device-management/managed-devices //새로운 디바이스를 생성

HTTP GET http://api.example.com/device-management/managed-devices/{id} //ID를 이용하여 디바이스를 요청
HTTP PUT http://api.example.com/device-management/managed-devices/{id} //ID를 이용하여 디바이스를 갱신
HTTP DELETE http://api.example.com/device-management/managed-devices/{id} //ID를 이용하여 디바이스 삭제

자원의 필터링을 위해서는 쿼리 파라미터를 사용한다.

자원을 정렬, 필터링 하거나 제한된 수량을 요청 해야 할 필요가 있다. 이때 신규 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

개발자들은 항상 시간에 쫓겨 개발 하게 된다. 그렇다 보니 이런 REST API의 이름을 정할 때 소홀 한 경우가 생긴다. 기능이 동작하는데 아무런 문제가 없기 때문일 때도, 너무 시간이 없어서 일 때도 있다. 필자 역시 그런 경우가 있었다. 이 글을 통해 조금이 나마 REST API 이름을 정하기 위해 고민하는 고통과 시간을 덜 수 있기를 바라며 마친다.

참조링크
‘REST Resource Naming Guide’ : https://restfulapi.net/resource-naming/

--

--