티스토리 뷰

API

[API] REST API 설계 해보기

Aaron_h 2019. 1. 9. 11:16
반응형


REST API 디자인 가이드

REST API를 어떻게 디자인 하는지 알아보고 좋은 REST API를 사용자들에게 제공할 수 있도록 해보자.


1. REST는 간략하고 직관적이게 디자인하자.
- REST API는 URL만 보고 URL이 의미하는 바를 알 수 있어야 한다.
- REST API는 길게 만들기 보다 짧게 만들어 제공하자. (최대 2 Depth를 권장 한다.)
- URL은 될 수 있으면 명사를 사용하자. (URL 작성되는 내용은 리소스 정보를 다루고 있기 때문에 동사보다는 명사가 더욱 어울린다. 단, 명사를 사용하게 되면 단수 보다는 복수형을 사용하자. 의미상 복수형이 더욱 어울리는 표현이기 때문이다.)

[잘못된 예 : HTTP Post로 모두 정의하고 get/set을 URL에 명시함으로서 행위를 구분하고자 하였다]

HTTP Post : /getDevices
HTTP Post : /setDevices


[올바른 예]

HTTP Get : /devices
HTTP Post : /devices/{cleaner}

- 리소스에 대한 행위는 HTTP에 Method를 통해 표현하는 것이 좋다.
CRUD(생성 : POST, 읽기 : GET, 수정 : PUT, 삭제 : DELETE)

[디자인 가이드]
1> create
1-1> HTTP POST /devices ------> devices 생성
1-2> HTTP POST /devices/cleaner ------> 에러
2> read
2-1> HTTP GET /devices ------> 모든 devices 정보 조회
2-2> HTTP GET /devices/cleaner ------> cleaner 정보 조회
3> update
3-1> HTTP PUT /devices ------> 모든 devices 업데이트
3-2> HTTP PUT /devices/cleaner ------> cleaner 정보 업데이트
4> delete
4-1> HTTP DELETE /devices ------> 모든 devices 삭제
4-2> HTTP DELETE /devices/cleaner ------> cleaner 삭제


2. 리소스간에 관계를 표현하는 방법을 알아보자.
- 우리가 API로 표현하고자 하는 리소스들은 서로 특정한 관계를 맺고 있다. 관계의 예를 들어보면 아래와 같다.
- devices/cleaner를 보면 devices와 cleaner라는 두가지 리소스가 표현되어 있다. 이 두 리소스는 상위 개념과 하위 개념이라는 관계를 가지고 있다고 말할 수 있다. cleaner는 devices에 속하는 개념이라고 보면 된다.
- 위에서 설명한 관계 이외에도 리소스간에는 다양한 관계가 존재할 수 있다. 그렇다면 james와 apple이라는 리소스로는 어떠한 관계를 표현할 수 있을까?james가 가지고 있는 apple, james가 좋아하는 apple 등..이 있을 수 있을 것이다. 이와 같은 관계를 REST API로 표현하는 방법을 알아보자.

2-1> 서브 리소스 표현 방법
- HTTP Get /users/tom/cars : 사용자 tom이 소유하고 있는 car들 정보 조회

2-2> 서브 리소스의 관계를 명시 하여 표현하는 방법
- HTTP GET /users/tom/likes/subjects : 사용자 tom이 좋아하는 과목 정보 조회
- 위와 같이 관계 "likes"를 URL에 명시적으로 표시해주면 된다.


*2-1의 표현은 has라는 소유의 관계를 생략하였다고 보면 된다.

그 외 관계는 2-2와 같이 구체적으로 표현하여 사용하는 것이 좋다.


3. 에러 처리는 어떻게 하는 것이 좋을까?
에러 처리는 HTTP Response Code의 정의를 따르자. 그리고 Response body에 error에 대한 구체적인 정보를 담아서 사용자에게 제공해주자.

3-1> HTTP Response Code : HTTP에 정의된 Response Code는 REST API에서 모두 사용 가능하다. 하지만 모두 사용하게되면 관리 및 운영에 어려움이 따를 수 있기 때문에 아래에 Code를 포함하여 제공하는 API서비스에 맞게 Response Code를 추가적으로 사용하도록 하자. (많다고 좋은 것만은 아니다)

- 200 : Success
- 400 : Bad Request
- 401 : Unauthorized
- 404 : Not found
- 500 : Internal Server Error

• HTTP Response Code 정보 : https://ko.wikipedia.org/wiki/HTTP_%EC%83%81%ED%83%9C_%EC%BD%94%EB%93%9C


• 참고 사항 : 기업별 사용하고 있는 HTTP Response Code 정보
- Google GData [10개] : 200, 201, 304, 400, 401, 403, 404, 409, 410, 500
- Netflix [9개] : 200, 201, 304, 400, 401, 403, 404, 412, 500



3-2> Error 상세 정보
HTTP Response Code는 사용자가 Request한 내용에 대한 처리 결과를 간략히 Code정보로 제공해 주는 것이다. Code 정보만으로는 에러에 대한 원인을 알기 쉽지 않으므로 에러에 대한 상세정보를 제공해 주는 것도 중요하다.


에러에 대한 상세 정보는 HTTP BODY에 정의해서 사용자에게 전달해 주면 된다.

예> 아래와 같이 Response Code 이외 Error에 대한 상세 정보를 전달해 주면 된다.
HTTP Status Code : 401
{
"error": {
"code": 403,
"message": "The request is missing a valid API key.",
"status": "PERMISSION_DENIED",
"code" : 12312312
"info" : www.test.com/doc/xxxx
}
}
-> 위 Error정보를 보면 code와 info 정보를 볼 수 있다. code는 서비스에서 관리하는 별도 error code정보이며 이와 같이 발생한 에러를 개선할 수 있는 정보를 사용자에게 제공하고자 하는 것이 info에 있는 링크 정보(Trouble Shooting 가이드)이다.


3-3> 주의 해야 할 사항
에러 메시지의 상세 정보에 Error Stack 정보를 출력하여 전달하는 경우가 있다.
이와 같이 Error Stack 정보를 사용자에게 공개할 경우 코드의 내부적인 구조가 외부에 노출되게 됨으로서 보안적인 이슈가 추가적으로 발생할 수 있다. Error Stack 정보가 개발시 꼭 필요하다면 API 서비스 개발시 dev 모드와 실제 운영할 production 모드를 구분하여 운영하고 목적에 따라 에러 메시지가 반환될 수 있도록 구현하는 것을 추천한다.

4. API 버전 관리하는 법을 알아보자.
API에 버전 관리는 아주 중요 하다. 그 이유는 이미 서비스 되고 있는 API에 새로운 기능이 추가 되어 새로운 버전이 나오게 되면 하위 호환성을 유지한 상태로 새로운 기능이 추가된 API 서비스를 사용자에게 제공해야 하기 때문이다. 즉, 같은 API라도 버전별로 다른 기능을 제공할 수 있도록 하는 것이 필요하다.

4-1> API 버전 정의 방법

- Facebook ? v=2.0
- https://speech.googleapis.com/v1/operations/123
- 조대협님 추천 : {servicename}/{version}/{REST URL} [예: api.server.com/account/v2.0/groups]


5. API에 페이징 개념 적용하는 법 알아보기
사용자의 요청 정보에 대해 많은 양의 정보를 리스트 형태로 서버가 응답해야 하는 경우 페이징 처리가 필요하다. (한번에 많은 많은 내용을 처리하는 것은 서버의 성능과 네트워크 부하면에서도 비효율적이며 요즘같은 빅데이터를 다루는 경우에는 처리 자체가 불가능한 경우가 많이 있다.)

5-1> 페이징 디자인

- Facebook : /record?offset=100&limit=25 : 100번째 부터 25개 레코드 조회
- LinkedIn : /record?start=50&count=25 : 50번째 부터 25개 레코드 조회

5-2> Partial Response 처리하기
- 리소스의 일부 정보만 조회 하고자 할 때 사용한다.
(사용자가 서버에 리소스에 대한 정보를 요청할 때 해당 리소스에 포함된 모든 정보를 요구하는 경우보다는 리소스에 해당하는 세부 몇 개의 정보만을 원하는 경우가 더 많다.)
- 예를 들면 user 리소스에 해당하는 정보는 id, pw, 이름, 주소, 전화번호 정보들이 있다고 해보자. 사용자는 user들의 정보 조회시 id와 이름 정보만 필요로 하는 경우가 있을 것이다. 이 때 user 사용자에게 user의 모든 정보를 제공하는 것보다 필요한 정보만 제공해준다면 전체 응답의 양을 대폭 줄일 수 있을 것이다.

[Partial Response 디자인 알아보기]
- Facebook : /terry/friends?fields=id,name
- Google : ?fields=title,media:group(media:thumnail)


6. API로 검색을 하고 싶다면?

사용자가 원하는 조건에 맞는 리소스를 조회 하고자 할 때를 의미한다.

6-1> API에서 검색 조건 디자인 하기
API에 검색 조건은 하나의 Query String으로 정의하여 사용하는 것이 좋다.

예 > /user?q=name%3Dcho,region%3Dseoul&offset=20&limit=10
위 예에서 검색 조건에 해당하는 부분은 URL Encode를 사용해 작성한 q=name%3Dcho,region%3Dseoul(실제 : q=name=cho,region=seoul)에 해당한다.

이와 같이 검색 조건을 별도로 정의하여 사용하는 이유는 아래와 같다.
/users?name=cho&region=seoul 이와 같이 검색 조건을 정의 하였다고 생각해보자. 검색 조건만 있을 경우에는 크게 문제가 되지 않지만 위 내용에 페이징 관련 내용을 추가하여 /users?name=cho&region=seoul&offset=20&limit=10와 같이 쓰게 된다면 어디까지가 검색 조건이고 어디까지가 페이징 조건인지 알 수 없게 된다. 이와 같은 문제 때문에 검색 조건을 별도로 정의하여 사용하는 것이다.

6-2>검색 범위별 디자인
검색을 리소스 단위로 할 수도 있지만 모든 리소스에 대한 검색을 하고 싶은 경우도 있을 것이다. 이와 같은 요구 사항을 만족하는 API 디자인을 알아보자

<전체 검색>
전체 리소스에 대한 검색을 요청하는 API의 경우에는 /search와 같은 전역 검색을 뜯하는 URL를 정의하여 사용하면 된다.
예 > /search?q=name%3Dlee : 이름이 lee인 모든 리소스를 조회

<리소스 검색>
특정 리소스에 대한 검색을 원할 경우에는 지금까지 예제로 들어왔던 것과 동일하게 리소스를 명시하고 뒤에 검색 조건을 작성하면 된다.
예 > /students?q=name%Dlee 이름이 lee인 학생들 조회


7. HATEOS (Hypermedia as the engine of application state)를 이용한 링크 처리 하기

HATEOS는 하이퍼미디어의 특징을 활용하여 HTTP Response에 리소스에 대한 Link 정보를 함께 탑재하여 사용자에게 전달해주는 것이다. 이와 같은 기능은 페이징 처리시 전/후 페이징에 대한 정보를 Link와 함께 전달해 주거나 리소스에 대한 디테일한 링크를 표시하는 목적으로 사용할 수 있다. HATEOAS를 API에 적용하면 가독성이 증대되는 장점이 있지만 응답 메시지가 다른 리소스 URL에 의존성이 생겨 구현이 다소 까다로워지는 단점이 있으니 알아두자.

(Spring 프레임워크에 HATEOAS 지원 내용 : http://spring.io/understanding/HATEOAS)


8. 단일 API 엔드 포인트를 제공하자

사용자에게 API를 제공 하게 될 경우 하나의 URL 표현으로 제공해 주는 것이 좋다.

market에 정보를 API로 서비스하는 회사가 있다고 가정하자. 이 회사는 food와 drink에 대한 API 서버를 별도로 구축하여 관리하고 있기에 food.supermarket.com, drink.supermarket.com 와 같이 각각의 URL을 분리하여 사용자에게 제공해주고 있다. 하지만 이와 같이 URL이 분리가 되어 있을 경우 개발자는 각각의 URL에 방화벽을 해제하고 서버 연결에 대한 관리를 별도로 해주어야 하는 리스크가 발생한다.

이와 같은 불편함을 보완하기 위해 API 서비스 제공자는 단일 API를 제공해주는 것이 좋다. food, drink가 각각 분리되어 서비스 되는 것은 api.supermarket.com/food, api.supermarket.com/drink와 같이 하나의 api.supermarket.com으로 제공해주는 것이 좋으며 이와 같이 구성하기 위한 방법과 장점은 아래와 같다.

8-1> 구성 방법 및 장점
HAProxy나 nginx를 이용하여 reverse proxy를 사용하자.

[설정]
api.supermarket.com/food는 food.supermarket.com으로 라우팅.
api.supermarket.com/drink는 drink.supermarket.com으로 라우팅.

[장점]
위와 같이 구성하면 API서버가 추가로 확장하더라도 유연하게 확장 및 운영이 가능하며 사용자는 단일 API를 변함없이 바라보기만 하면된다는 장점이 있다.
추가적으로 단일 엔드포인트를 제공하면 부하 분산 및 로그를 통한 Audit(감사)를 쉽게 할 수 있다는 장점이 있다.


반응형

'API' 카테고리의 다른 글

RPS와 TPS의 차이점 무엇일까?  (0) 2024.01.25
[부하테스트] Locust란 무엇인가?  (0) 2023.12.12
[API] REST API 보안  (0) 2019.01.15
[API] REST API (특성)  (0) 2018.12.26
[API] REST API (개념 및 구성 요소)  (0) 2018.12.24
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함