RESTful한 API를 설계하기 위한 기준을 세워봅시다!
Riot Games의 API 문서를 참고했습니다.
URI를 통해 알 수 있는 것
- 책임
- 깊이
- 도메인과 도메인의 관계
예를 들어, TeacherReview는 선생님에 대한 리뷰이고 선생님 컨트롤러에 있겠다는 것을 파악할 수 있습니다.
깊이란 뎁스에 따라 점점 좁혀지는 URI를 뜻하며, pk면 바로 /id를 쓰고, pk가 아니면 /by-phone/{phone} 이런 식으로 쓸 수 있습니다.
도메인 간의 관계가 나타납니다. 1:n, n:1, m:n, 1:1
도메인이 정의되면 서로의 관계들을 파악하고 설계할 수 있습니다.
응답 내리는건 단건 or 복수건입니다. 복수건으로 한 건을 그냥 보내면 되니까 애매하면 복수건으로 내리면 됩니다.
데이터 가져오는건 무조건 GET, 그외에 민감정보를 포함해서 요청해야 하는 것은 POST를 사용합니다.
우리 팀의 URI CONVENTION
- URI에 API를 표기합니다.
- open-api or api
- 생략 or admin or app
- 생략되는 경우 있음. ex. 메인화면에는 로그인하지않은 유저도 접근할 수 있음.
- service name
- URI 경로에 버전을 표기합니다.
- URI는 kebab-case를 사용하며, Parameter와 Body에서 사용되는 변수와 객체의 이름은 camelCase를 사용합니다.
- 자원은 복수형으로 표현합니다.
- 대부분의 API는 어느 자원의 그룹에서 특정 자원 ID를 통해 어떤 작업을 진행한다는 의미를 내포하고 있습니다.
- RESTful API 설계 원칙을 따르는 많은 가이드와 베스트 프랙티스 문서에서 리소스를 복수형으로 사용하는 것을 권장하며 이는 RESTful 디자인 패턴의 일관성과 예측 가능성을 높이게 된다고 합니다.
- 일관된 용어를 사용합니다.
- ex) 회원을 member로 표현하기로 했다면 회원을 지칭하는 모든 용어를 member로 사용해야 합니다.
- Path Variable, Query String
- 필수값인 경우 path variable을 사용하고, optional한 값인 경우 query string을 사용합니다.
- 복잡한 행위를 표현하기 위해서는 URI에 동사를 포함시킵니다.
- 단순 CRUD 외에 다양한 도메인의 행위를 표현하기 위해 URI에 동사를 포함시키는 것을 허용합니다.
- HTTP Method만으로 행위 설명 어려울 시 동사를 통해 행위를 명시합니다.
- ex) 주문 취소와 주문 삭제는 다른데, HTTP Method만으로 이 행위를 함께 표현하기가 어렵다. 따라서 /자원/{자원ID}/행위 형태로 URI를 설계한다.
- POST /order/{orderId}/cancel
- ex) 주문 취소와 주문 삭제는 다른데, HTTP Method만으로 이 행위를 함께 표현하기가 어렵다. 따라서 /자원/{자원ID}/행위 형태로 URI를 설계한다.
- URI 예시: open-api/product/v1/teachers/{teacher-id}/courses
- response: List<teacherCourse>
- TeacherController에 있는 API
[GET] 예시
1.하나의 Collection 데이터 전체 조회
- 예시 : /teachers
- Controller : teacherController
- 리턴값 : Teacher List
2.하나의 Collection에 PK로 Document 조회
- 예시 : /teachers/{teacherId}
- Controller : teacherController
- 리턴값 : Teacher 단건
3.하나의 Collection에 PK가 아닌 자원으로 데이터 조회
- 예시 : /teachers/by-phone/{phone number}
- Controller : teacherController
- 리턴값 : Teacher 단건
4.하나의 Collection에 PK > 내부 Collection 조회
- 예시 : /teachers/{teacherId}/reviews
- Controller : teacherController
- 리턴값 : TeacherReview List
- 도메인 관계 : teacher:review = 1:n
5.하나의 Collection에 PK > 내부 Collection의 PK로 조회
예시 : /teachers/{teacherId}/reviews/{reviewId}Controller : teacherController리턴값 : TeacherReview 단건도메인 관계: teacher:review = 1:1
6.하나의 Collection에 PK가 아닌 자원으로 데이터 조회 > 내부 Collection 조회
- 예시 : /teachers/by-phone/{phone number}/reviews
- Controller : teacherController
- 리턴값 : TeacherReview List
7.하나의 Collection에 PK가 아닌 자원으로 데이터 조회 > 내부 Collection의 PK로 조회
예시 : /teachers/by-phone/{phone number}/reviews/{reviewId}Controller : teacherController리턴 : TeacherReview 단건
8.하나의 Collection에 PK가 아닌 자원으로 데이터 조회 > 내부 Collection의 PK가 아닌 자원으로 데이터 조회
예시 : /teachers/by-phone/{phone number}/reviews/by-nickname/{nickname}Controller : teacherController리턴값 : TeacherReview 단건
9. 여러 Collection에 대한 내부 Collection 조회
- 예시 : /teachers/reviews
- Controller : teacherController
- 리턴값 : TeacherReview List
- 도메인 관계 : teacher:review = m:n
---수정---
리소스 URI를 리소스/리소스ID/하위리소스보다 더 복잡하게 구성하지 않는 것이 좋다는 조언을 바탕으로 예시를 몇개 삭제했습니다.
CQRS 예시
CQRS란 Command and Query Responsibility Segregation 의 약자로, 읽기 작업(쿼리)과 쓰기 작업(명령)을 명확히 분리하는 패턴을 말합니다.
이 프로젝트에서는 API 엔드포인트에 CQRS 패턴을 적용했습니다. 이를 통해 읽기와 쓰기 작업의 책임을 명확히 분리하여 코드의 가독성과 유지보수성을 향상시켰고, 미래의 확장성을 고려하여 설계했음을 알 수 있습니다. 현재는 프로젝트의 복잡도가 낮아 데이터베이스를 분리하지 않았지만, 시스템이 성장하고 데이터 트래픽이 증가하면 읽기와 쓰기 데이터베이스를 분리하여 성능을 최적화할 수도 있습니다. 이처럼 필요할 때 쉽게 서비스를 확장할 수 있도록 시스템을 설계하였습니다.
예를 들어, 다음과 같이 나눠둔 서비스에 각각 필요한 쿼리와 커맨드 API를 요청하는 식으로 활용합니다.
- review-Query-service
- review-Command-service
참고: https://jojoldu.tistory.com/m/783
'🏃♀️ 활동 > 프로젝트 작업일지' 카테고리의 다른 글
[그만좀늦자] 배포하기! (0) | 2024.09.02 |
---|---|
WeWish: K-Registry App (1) 프로젝트 시작 (0) | 2023.01.03 |
Project: Ants vs SomeBees(2) (0) | 2022.07.26 |
Project: Ants vs SomeBees(1) (0) | 2022.07.26 |
Project 2: CS 61A Autocorrected Typing Software(1) (0) | 2022.07.11 |