RESTful API 이해 및 사용법
Yi Sun
December 2, 2022
만물인터넷 시대에는 다양한 API가 존재하며, 이를 표준화하는 것이 중요합니다. RESTful API는 가장 인기 있는 API 아키텍처 스타일 중 하나로, 클라이언트와 서버의 관심사를 분리하여 프론트엔드와 백엔드가 별도로 반복할 수 있게 하여 효율성을 높일 수 있습니다. 그 무상태(stateless) 특성은 애플리케이션을 더 확장 가능하게 만들고, 캐싱 정책을 더 쉽게 구현하여 사용자 경험과 성능을 향상시킬 수 있습니다. 이 글에서는 RESTful API가 무엇인지, 그리고 어떻게 사용할 수 있는지 소개하겠습니다.
API란 무엇인가
API가 무엇인지 잠시 제쳐두고, 우리가 일상에서 정보를 전달하는 방법에 대해 이야기해 보겠습니다.
가게 주인에게 돈을 주고 배터리를 사겠다고 말하면, 주인은 돈을 받고 선반에서 배터리를 찾아 당신에게 건네줍니다. 배터리 구매 거래가 성공적으로 완료된 것입니다.
반면, 컴퓨터 소프트웨어는 API를 통해 이를 완료합니다. 위키피디아 정의부터 시작해 보겠습니다:
애플리케이션 프로그래밍 인터페이스(API)는 두 개 이상의 컴퓨터 프로그램이 서로 통신하는 방법입니다. 이는 소프트웨어 인터페이스의 일종으로, 다른 소프트웨어에 서비스를 제공합니다.
소프트웨어 A가 API를 통해 소프트웨어 B에 요청을 보내면, 소프트웨어 B는 자원을 조회한 후 API를 통해 A에게 응답을 반환합니다.
소프트웨어 A가 API를 통해 소프트웨어 B에 요청을 보내는 것은 당신이 상사에게 배터리가 필요하다고 말하는 것과 같고, 소프트웨어 B가 데이터를 소프트웨어 A에게 반환하는 것은 상사가 배터리를 찾아 당신에게 주는 것과 같습니다.
이 과정에서 소프트웨어 B는 소프트웨어 A가 왜 데이터를 원하는지 알 필요가 없으며, 마치 가게 주인이 당신이 왜 배터리를 샀는지 묻지 않는 것과 같습니다. 소프트웨어 A도 소프트웨어 B가 어떻게 데이터를 찾았는지 알 필요가 없으며, 마치 당신이 배터리를 살 때 주인에게 배터리를 어디서 구입했는지 묻지 않는 것과 같습니다. 각 소프트웨어는 API를 통해 서로 정보를 전달하며, 각자 자신의 일을 하여 프로그래밍 세계를 질서 있고 신뢰할 수 있게 만듭니다.
RESTful API란 무엇인가
Roy Fielding은 그의 2000년 박사 논문 "아키텍처 스타일과 웹 기반 소프트웨어 아키텍처 설계"에서 REST(Representational state transfer)를 정의했으며, REST 아키텍처 스타일은 여섯 가지 지침을 정의합니다. 이 지침 중 일부 또는 전부를 준수하는 시스템을 일반적으로 RESTful이라고 부릅니다.
(출처: Seobility)
RESTful API의 제약 조건
제약 조건 | 세부 사항 | 이점 |
---|---|---|
클라이언트-서버 아키텍처 | 사용자 인터페이스 문제와 데이터 저장 문제를 분리하여 여러 플랫폼에서 사용자 인터페이스의 이식성을 높이고, 서버 구성 요소를 단순화하여 확장성을 향상시킵니다. | 1. 클라이언트와 서버의 분리. 2. 사용자 플랫폼의 이식성 향상. 3. 서버 측 확장성 향상. |
무상태성 | 클라이언트에서 서버로의 각 요청은 요청에 필요한 모든 정보를 포함해야 하며, 서버에 저장된 컨텍스트를 사용해서는 안 되며, 세션 상태는 완전히 클라이언트에 저장됩니다. | 1. 확장이 쉽고, 세션 의존성이 없어 어떤 서버도 어떤 요청을 처리할 수 있습니다. 2. 캐싱이 쉬워 프로그램 성능을 향상시킬 수 있습니다. |
캐시 가능성 | 요청 또는 응답의 데이터가 암시적 또는 명시적으로 캐시 가능 또는 캐시 불가능으로 표시되어야 합니다. 응답이 캐시 가능한 경우, 클라이언트 캐시는 후속 동등한 요청에 대해 해당 응답 데이터를 재사용할 권한을 부여받습니다. | 1. 대역폭 감소. 2. 지연 시간 감소. 3. 서버 부하 감소. 4. 네트워크 상태 숨김. |
계층화 시스템 | 구성 요소의 동작을 제한하여 아키텍처가 계층으로 구성될 수 있도록 하여 각 구성 요소가 상호 작용하는 즉각적인 계층을 넘어 "볼" 수 없게 합니다. 시스템 지식을 단일 계층으로 제한함으로써 전체 시스템의 복잡성을 줄이고 하위의 독립성을 촉진합니다. | 1. 전체 시스템의 복잡성 감소. 2. 하위의 독립성 촉진. 3. 로드 밸런싱을 쉽게 구현할 수 있습니다. 4. 비즈니스 로직과 보안 정책을 분리할 수 있습니다. |
코드 온 디맨드 (선택 사항) | 클라이언트 기능을 확장하기 위해 애플릿 또는 스크립트 형태로 코드를 다운로드하고 실행할 수 있도록 합니다. | 1. 시스템의 확장성 향상. |
통일된 인터페이스 | 네 가지 주요 포인트를 포함합니다: 1. 요청에서의 리소스 식별. 클라이언트는 요청에 포함된 URI를 통해 리소스를 식별할 수 있으며, 서버 측 리소스와 클라이언트 요청 리소스를 분리합니다. 2. 표현을 통한 리소스 조작. 클라이언트가 리소스의 표현(예: URI)을 가지고 있다면, 리소스를 수정하거나 삭제하기에 충분한 정보가 있습니다. 3. 자기 설명적 메시지. 모든 메시지는 클라이언트가 메시지를 어떻게 처리할지 알 수 있는 충분한 정보를 포함합니다. 4. 애플리케이션 상태의 엔진으로서의 하이퍼미디어 (HATEOAS). 클라이언트는 서버가 반환한 리소스 링크를 통해 사용자에게 모든 리소스를 제공하기 위해 추가 코딩이 필요하지 않습니다. | 1. 전체 시스템 아키텍처 단순화. 2. 상호 작용의 가시성 향상. |
RESTful API 모범 사례
구성 요소 간의 통일된 인터페이스 강조는 REST 아키텍처 스타일을 다른 웹 기반 스타일과 구별하는 핵심 기능이며, 이 기능을 기반으로 여기에 모범 사례를 정리하여 API를 더 잘 설계하는 데 도움을 드립니다.
경로 이름에 동사 사용 피하기
리소스 조작 행동을 표현하기 위해 HTTP 메서드를 사용하고, 경로에 행동 동사를 정의하지 마세요.
// 좋은 예
curl -X GET http://httpbin.org/orders
// 나쁜 예
curl -X GET "http://httpbin.org/getOrders"
- GET을 사용하여 지정된 URI의 리소스 정보 가져오기
// 현재 시스템의 모든 주문 정보를 가져오는 것을 나타냄
curl -X GET http://httpbin.org/orders
// 주문 번호 1의 주문 상세 정보를 가져오는 것을 나타냄
curl -X GET http://httpbin.org/orders/1
- POST를 사용하여 지정된 URI에서 리소스 생성
// 이름이 order인 리소스를 생성하는 것을 나타냄
curl -X POST http://httpbin.org/orders \
-d '{"name": "awesome", region: "A"}' \
- PUT을 사용하여 지정된 URI에서 리소스 생성 또는 완전히 대체
// id가 1인 주문의 데이터를 대체하는 것을 나타냄
curl -X PUT http://httpbin.org/orders/1 \
-d '{"name": "new awesome", region: "B"}' \
- PATCH를 사용하여 리소스의 부분 업데이트 수행
// id가 1인 주문의 region 필드를 변경하고 나머지 데이터는 그대로 유지하는 것을 나타냄
curl -X PATCH http://httpbin.org/orders/1 \
-d '{region: "B"}' \
- DELETE를 사용하여 지정된 URI에서 리소스 제거
// id가 1인 주문을 삭제하는 것을 나타냄
curl -X DELETE http://httpbin.org/orders/1
URI는 복수형 사용
특정 유형의 리소스에 접근한다는 것을 나타내기 위해 단수형을 사용하려면:
curl -X GET "http://httpbin.org/order"
단수형을 사용하면 시스템에 단 하나의 주문만 있다고 오해할 수 있지만, 복수형을 사용하면 이해가 훨씬 원활해집니다.
curl -X GET "http://httpbin.org/orders"
HTTP 상태 코드 잘 활용하기
HTTP 표준은 상태 코드를 정의하며, 크게 다음과 같이 분류할 수 있습니다:
상태 코드 | 의미 |
---|---|
2xx | 성공, 작업이 성공적으로 수신 및 처리됨 |
3xx | 리디렉션, 요청을 완료하기 위해 추가 작업이 필요함 |
4xx | 클라이언트 오류, 요청에 구문 오류가 포함되었거나 요청을 완료할 수 없음 |
5xx | 서버 오류, 서버가 요청을 처리하는 동안 오류가 발생함 |
표준 상태 코드를 사용하면 개발자는 즉시 문제를 식별할 수 있으며, 다양한 유형의 오류를 찾는 시간을 줄일 수 있습니다.
버전 관리
비즈니스 요구 사항이 변경됨에 따라 이미 온라인 상태인 API도 그에 따라 조정해야 할 가능성이 높습니다. 우리의 API가 제3자에 의해 사용되는 경우, 모든 클라이언트가 우리 API의 변경에 따라 변경하도록 하는 것은 불가능하므로, API 버전 관리 개념을 도입하여 역사적 API의 정상적인 사용을 보장하고 새로운 비즈니스 요구 사항을 충족하기 위해 새로운 API를 반복할 수 있습니다.
일반적인 버전 관리 방법은 다음과 같습니다:
- 요청 경로를 통한 버전 관리
// v1 API 요청
curl http://httpbin.org/v1/orders
// v2 API 요청
curl http://httpbin.org/v2/orders
- 쿼리 매개변수를 통한 버전 관리
// v1 API 요청
curl http://httpbin.org/orders?version=v1
// v2 API 요청
curl http://httpbin.org/v2/orders?version=v2
- 헤더를 통한 버전 관리
// v1 API 요청
curl http://httpbin.org/orders -H "custom-version: v1"
// v2 API 요청
curl http://httpbin.org/orders -H "custom-version: v2"
APISIX가 RESTful API를 어떻게 강화하는가
Apache APISIX는 동적, 실시간, 고성능 API 게이트웨이입니다. 이는 모든 RESTful API 서비스 앞에서 실행될 수 있으며, 플러그인을 사용하여 새로운 서비스를 추가하고 기능을 확장할 수 있어 계층화 시스템의 RESTful 정의와 일치합니다. 또한, RESTful API 정의를 따르지 않는 일부 역사적 서비스에 대해서도 APISIX는 원래 비즈니스 코드를 변경하지 않고 인터페이스를 변환하여 통일된 인터페이스의 REST 제약 조건을 충족시켜 API가 RESTful API 사양을 더 잘 준수하도록 도울 수 있습니다.
계층화 시스템: 비즈니스 로직과 보안 로직 분리 지원
비즈니스 로직 구현에만 집중할 수 있으며, 인터페이스의 보안 로직은 APISIX 인증 클래스 플러그인(예: key-auth)에 맡길 수 있습니다. APISIX는 다양한 인증 플러그인을 지원하며, 예를 들어 openid-connect를 사용하면 다음과 같습니다:
APISIX(API 게이트웨이)를 사용하여 비즈니스 서버 앞에 인증 로직을 추가하면 업스트림 서비스를 보호할 수 있으며, 이 아키텍처 패턴은 비즈니스 로직과 보안 로직을 분리하는 데 좋은 방법입니다.
계층화 시스템: 다중 로드 밸런싱 프로토콜 지원
APISIX는 API 게이트웨이로, 클라이언트와 서버 사이에 설정되어 다양한 로드 요구 사항을 충족할 수 있습니다. 심지어 사용자 정의 로드 밸런싱 로직을 설정할 수도 있습니다.
지원되는 로드 밸런싱 알고리즘은 다음과 같습니다:
roundrobin
: 가중치를 고려한 라운드 로빈 밸런싱.chash
: 일관된 해시.ewma
: 최소 지연 시간을 가진 노드를 선택. 자세한 내용은 EWMA 차트 참조.least_conn
:(active_conn + 1) / weight
값이 가장 낮은 노드를 선택. 여기서 active_conn은 요청에 의해 사용 중인 연결로, Nginx의 개념과 유사합니다.require("apisix.balancer.your_balancer")
를 통해 로드되는 사용자 정의 로드 밸런서
통일된 인터페이스: 역사적 API를 더 RESTful하게 만들기
오랫동안 존재해 왔고 RESTful API 지침을 잘 따르지 않는 역사적 API의 경우, APISIX를 통해 새로운 API를 재포장하여 원래 API 로직을 변경하지 않고도 다양한 비즈니스 시나리오를 충족시킬 수 있습니다.
- proxy-rewrite를 사용하여 클라이언트 요청 재작성
위에서 언급했듯이, 경로에 동사를 포함시키지 않아야 합니다.
예를 들어, 역사적 API에 /getOrder
인터페이스가 있다면, proxy-rewrite 플러그인을 통해 API 요청을 역사적 API로 프록시할 수 있습니다.
curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"methods": ["GET"],
"uri": "/orders",
"plugins": {
"proxy-rewrite": {
"uri": "/getOrder",
"scheme": "http",
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:80": 1
}
}
}'
API 버전 관리 작업에도 이 플러그인을 사용할 수 있습니다.
- response-rewrite 플러그인을 사용하여 서버 응답 재작성
역사적 API가 비표준 응답 상태 코드를 가지고 있는 경우, response-rewrite를 사용하여 응답을 프록시하여 응답 상태 코드를 수정할 수 있습니다.
curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"methods": ["GET"],
"uri": "/orders",
"plugins": {
"response-rewrite": {
"status_code": 201,
"body": "{\"code\":\"ok\",\"message\":\"new json body\"}",
"vars":[
[ "status","==",200 ]
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:80": 1
}
}
}'
위 예제는 /orders
경로를 요청하는 API에서 상태 코드 200을 201로 수정하는 요청을 나타냅니다.
APISIX는 매우 다양한 플러그인을 지원하므로, 더 많은 활용 방법을 탐색해 보시길 기대합니다.
요약
이 글에서는 API가 무엇인지, RESTful API가 무엇인지, 그리고 그 모범 사례를 소개했습니다. 또한, APISIX를 통해 비즈니스 로직과 보안 로직을 분리하는 방법과, 원래 비즈니스 코드를 변경하지 않고 역사적 API 서비스를 더 RESTful하게 만드는 방법도 소개했습니다. 이 글이 RESTful API를 이해하는 데 도움이 되길 바랍니다.