개발을 하다보면 가장 어려운 것 중에 하나가 바로 네이밍입니다. 어쩔 때에는 변수와 함수 이름을 고민하는 것이 개발 시간의 상당 부분을 차지하기도 하는데요. 이러한 네이밍에 대한 고민은 단순히 함수와 변수 이름에만 그치지 않습니다.
API를 만들다 보면 한 부분에서 네이밍에 대한 고민을 추가적으로 하게 되는데요. 바로 api url 주소 구성/네이밍에 대한 고민입니다. REST 방식으로 api를 만들면 url 주소에 대해 고민하고, graphql 방식으로 만들면 쿼리나 뮤테이션 이름에 대해 결정해야 하는데요. 오늘은 REST API의 URL 컨벤션에 대해 다루어보겠습니다.
사실 네이밍에 정답은 없습니다. 그러나 고민하시는 분들의 결정에 도움이 될 수 있도록 스택오버플로우 질의응답, 개발 블로그, 유명한 프로젝트의 api 네이밍 등을 참고하여 콘텐츠를 작성해보았습니다.
REST API에서는 post, put, get 등으로 CRUD (Create, Read, Update, Delete)를 할 수 있습니다. 유저 db에 대한 작업을 예시로 생각해보면, 유저를 생성하는 api, 유저를 불러오는 api, 유저 정보를 수정하는 api, 유저를 제거하는 api가 있을 수 있죠.
그렇다면 유저를 생성하거나, 특정 id를 가진 유저를 불러오는 api 주소는 어떻게 구성할 수 있을까요?
아마 가장 먼저 고민하게 되는 부분이 단수와 복수일 것인데요. 다음과 같은 선택지가 있을 것입니다.
- 유저 생성: (POST) /user, /users
- 유저 조회: (GET) /user/123, /users/123
제가 가장 설득력있게 납득한 방식은 스택오버플로우에서 많은 추천을 받은 '코드에 대응하는 방식'입니다.
GET /users <---> users
POST /users <---> users.push(data)
GET /users/12 <---> users[12]
DB의 유저 Table/Collection을 생각하면 보다 쉽게 이해가 됩니다. (RDBMS에서는 Table, MongoDB에서는 Collection 이라고 합니다)
우선 유저 array를 받아오는 요청은 여러 유저 정보를 받아오는 것이니 users가 자연스럽습니다. (GET /users)
그리고 유저를 생성하는 것도 유저 array에 하나의 유저를 추가하는 것이니 /users 에 요청을 날리는 것이죠.
특정 id의 유저를 받아오는 api도 유저 array 중에서 고르는 것이기에 /users/:id 가 꽤나 자연스럽게 느껴집니다.
사실 몇몇 글을 살펴보면 복수를 선호하지만 단수를 쓰는 것도 큰 상관은 없다는 의견도 많습니다. 다만 이들은 모두 공통적으로 단수와 복수를 혼합해서 사용하는 것은 지양해야 한다고 말하죠!
(혼용해서 사용하게 된다면, 기준이 없어지고 새로 api를 만들거나 api를 가져다 쓸 때 쉽게 헷갈리거나 실수하게 되기 때문입니다)
REST API 네이밍을 위해서는 동사보다는 명사를 사용하는 것이 좋습니다.
여러가지 이유가 있지만, 우선 동사를 사용하면 같은 리소스에 대한 동작도 이름이 매우 달라지게 됩니다. 반면 명사를 사용하면 보다 api를 규칙적이고 깔끔하게 관리할 수 있죠.
GET /getUsers ---> GET /users
POST /createNewUser ---> POST /users
GET /getUserById/12 ---> GET /users/12
또한 명사는 프로퍼티를 표현하기에 훨씬 적합합니다. 만약 아래 예시에 account id까지 추가로 들어간다면 동사로 더이상 어떻게 표현해야 할지도 모르겠네요...!
GET /getAccountsOfUserByUserId/123 ---> GET /users/123/accounts
만약 주소에서 표현하는 리소스가 길어지는 경우, 하이픈(-)을 이용해서 구분하는 것이 가독성에 좋습니다.
GET /devicemanagement/manageddevices ---> GET /device-management/managed-devices
사실 밑줄(언더스코어, _)을 사용하여 구분할 수도 있습니다. 그러나 브라우저가 자체적으로 url 주소에 대해서는 자동적으로 밑줄을 표시하는 경우가 있습니다. (맨 아래 참고 자료 링크만 보아도 url 주소에 밑줄이 그어져 있죠) 이러한 경우 url에 밑줄이 포함된다면, 폰트에 따라서 아예 밑줄이 빈 칸 처럼 보일 수도 있는 것입니다.
이런 혼란을 피하기 위해서는 밑줄보다는 하이픈이 낫겠죠!
일반적으로 URI 경로에서는 소문자를 사용하는 편입니다. 사실 URL에서 프로토콜과 호스트 주소는 대소문자를 구분하지 않지만, 리소스 경로 부분은 운영체제 등에 따라 구분하는 경우가 있습니다. 윈도우 운영체제라면 디렉터리나 파일이름에서 대소문자를 구분하지 않으나, 리눅스 혹은 유닉스 계열의 서버라면 대소문자를 구분하는 것이죠.
그러니 혹시 모를 상황을 대비하고 일관성을 유지하기 위해서라도 소문자로 통일하는 것이 더 선호됩니다.
api를 설계하다보면 필터링이 필요한 경우가 많이 존재합니다. 이런 경우에는 새로운 api를 만들기보다는 쿼리 파라미터를 활용하는 것이 좋은데요. 동일한 컬렉션/테이블을 타겟으로 하는 api는 하나로 통일되는 것이 장려된다는 뜻입니다.
(이는 필터링뿐만 아니라 정렬이나 페이지네이션 등에서도 마찬가지입니다)
/users/region/ko ---> /users?region=ko
/users/gender/female ---> /users?gender=female
/users/region/ko/gender/female ---> /users?region=ko&gender=female
오늘은 한 번 REST 리소스 네이밍 컨벤션에 대해 살펴보았는데요. 몇 가지 컨벤션을 익히고 api를 설계하다보면, 고민하는 시간이 줄고 보다 편하게 코드를 작성할 수 있을 것입니다. 그러면 오늘도 해피코딩하세요!
기타 참고 자료
- https://restfulapi.net/resource-naming/
- https://gearheart.io/articles/restful-api-design-best-practices/
react native 이미지 업로드 기능 만들기! (expo) (2) | 2022.01.30 |
---|---|
NodeJS 이미지 업로드 기능 만들기 (AWS S3 활용하기) (0) | 2022.01.30 |
Express에서 JWT 토큰 인증 미들웨어 만들기 (Typescript 적용까지) (1) | 2021.12.22 |
Express에서 Error handler 추가하여 try, catch 생략하기! (1) | 2021.12.22 |
React Native (Expo)에 구글 가입 기능 추가하기 (9) | 2021.12.22 |
댓글 영역