REST API란 무엇인가?

REST API란?


REpresentational State Transfer의 약자로, 서버의 자원을 정의하고, 자원에 대한 주소를 지정하는 방법(표기법)을 말한다. 2000년, 아파치 HTTP 서버 프로젝트의 공동설립자인 Roy fielding(로이 필딩)에 의해 처음 소개가 되었는데, 이 분은 HTTP/1.0,1.1 스펙 작성에 참여하신 분이다.

그는 웹의 장점을 최대한 활용할 수 있는 Architecture로써 REST를 소개하면서, REST API 규칙을 만들었다. 이런 REST API 규칙을 잘 지킨 서비스 디자인을 “RESTful”하다고 표현한다. REST API는 HTPP 프로토콜을 정확히 의도에 맞게 활용하여 디자인하게 유도하기 때문에, 디자인 기준이 명확해지고, 의미적인 범용성을 지닌다. 즉, 서버가 이해하기 쉽게 자원에 대한 주소를 지정하는 표기법이 REST API이다.


REST API 구성 요소


REST API를 구성하는 것은 다음과 같이 3가지가 있다.

  • 자원(Resource)
  • 행위(Verb)
  • 표현(Representation)


자원(Resource)


자원(Resource)이란, 해당 소프트웨어가 관리하는 모든 것이 될 수 있다.
JSON, XML 등의 문서가 될 수 있고, 그림파일이 될 수도 있다.
즉, 어떤 데이터(문서, 파일, 비디오 등)를 말한다.

예를 들어, 서버 데이터베이스에 사용자들에 대한 정보가 들어가 있다면, 이 사용자들의 정보가 데이터이기 때문에, 자원(Resource)이 된다. 이때, 이 사용자들에 대한 데이터를 대표하는 이름을 users라고 해보자. 만약, 이 사용자들 중에서 어떤 한 명의 사용자에 대한 자원을 얻고자 한다면 어떻게 해야할까? 그럴때는, users/id 처럼, 사용자들 중 특정 id로 사용자를 구분해서 사용할 수 있다.

자원(Resource)은 HTTP URI로 표현한다. 예를 들어, http://localhost:4000/users/1 이런식으로 작성하며, 이 URI를 이용하여 원하는 자원(Resource)에 접근할 수 있다.


행위(Verb)


REST API에서 말하는 행위(Verb)는 자원에 대한 행위를 말한다. 즉, HTTP Method를 사용해서 자원을 얻거나, 만들거나, 변경하거나, 삭제하는 등의 행위를 할 수 있다.

HTTP Method 중 대표적으로 자주 사용되는 메서드는 다음과 같다.

  • GET : 서버 자원을 가져오고자 할 때 사용한다.(Retrieve: 모든/특정 자원을 조회)
  • POST : 서버에 자원을 새로 등록하고자 할 때 사용한다.(Create: 자원을 생성)
  • PUT : 서버의 자원을 새로 요청한 자원으로 변경하고자 할 때 사용한다.(Update: 자원을 갱신)
  • PATCH : 서버 자원의 일부만 수정하고자 할 때 사용한다.
  • DELETE : 서버의 자원을 삭제하고자 할 때 사용한다.(Delete: 자원을 삭제)

위 4가지(GET/POST/PUT/DELETE)를 이용해서 CRUD를 구현할 수 있다.


표현(Representation)


표현(Representation)은 자원에 대한 행위의 내용을 말하는데, 이때 내용은 서버에 요청할 때 무엇인가를 새로 생성하거나, 변경할 때 필요한 내용을 말한다. 이때, HTTP Message인 payload를 사용한다.

서버 자원에 무언가 새로운 것을 생성할 때, HTTP Method 중 POST와 함께 payload를 같이 요청한다. 예를 들어, 사용자들에 대한 정보가 있는 users에 새로운 사용자 정보를 생성하고 싶다면, 이 새로운 사용자에 대한 정보를 새로 만들어서 추가해줘야 하는데, 이것을 payload라고 한다.

1
2
3
4
5
6
7
POST http://localhost:4000/users/

{
"id": 1,
"name: "Ro",
"country": "Korea"
}

위 객체를 payload라고 하는데, 위 자원(http://localhost:4000/users/) 에 POST 방식으로 위 payload(객체)와 함께 서버에 요청을 해야한다.


REST API 중심 규칙


위와 같은 내용을 잘 정리한 것이 REST API 중심 규칙이다.
REST한 API를 설계하기 위한 중심 규칙은 대표적으로 2가지이다.


1. URI는 정보의 자원을 표현해야 한다.


URI는 정보의 자원을 표현하는데 중점을 두어야 하기 때문에, 어떤 행위를 나타내는 동사보다는 자원의 의미를 명확히 전달하기 위해 명사를 사용해야 한다.

id가 1인 사용자에 대한 자원을 얻고 싶다면, 다음과 같이 작성해야 한다.

1
GET /users/1

행위를 나타내는 다음과 같은 URI는 잘못된 방법이다.

1
2
GET /getUsers/1
GET /users/show/1


2. 자원에 대한 행위는 HTTP Method로 표현한다.


1
DELETE /users/1


REST API Architecture


REST API는 자원과 메서드만 보고 요청의 내용을 명확하게 알 수 있다는 것이 장점이다.

이런 REST API의 Architecture를 보면 다음과 같다.

REST API Architecture
출처: REST API Architecture

어떤 클라이언트(웹브라우저/안드로이드 앱/ios 앱)에서 서버에 요청을 할 때 HTTP 통신을 하고, HTTP Method를 사용하여 원하는 행위를 하여 서버로부터 응답을 받는다.


REST API 사용 예제


Ajax를 사용하여 REST API를 어떻게 사용하는지 알아보자.

사용자에 대한 정보인 users 데이터는 다음과 같다고 해보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
"users": [
{
"id": 1,
"name": "Ro",
"country": "Korea"
},
{
"id": 2,
"name": "John",
"country": "Canada"
},
{
"id": 3,
"name": "Doh",
"country": "China"
},
{
"id": 4,
"name": "Hitaro",
"country": "Japan"
}
]
}


1. GET


1-1. users 자원에서 모든 사용자의 정보를 가져온다.(모든 사용자)

1
GET http://localhost:4000/users

위와 같이 users에 대한 자원을 GET하게 되면 다음과 같이 모든 users에 대한 정보를 가져올 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[
{
"id": 1,
"name": "Ro",
"country": "Korea"
},
{
"id": 2,
"name": "John",
"country": "Canada"
},
{
"id": 3,
"name": "Doh",
"country": "China"
},
{
"id": 4,
"name": "Hitaro",
"country": "Japan"
}
]

이것을 코드로 작성하면 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
var req = new XMLHttpRequest();
req.open('GET', 'http://localhost:4000/users');
req.send();

req.onreadystatechange = function (e) {
if (req.readyState === XMLHttpRequest.DONE) {
if(req.status === 200) {
console.log(req.responseText);
} else {
console.log("Error!");
}
}
};


1-2. users 자원에서 id가 1인 사용자의 정보를 가져온다.(특정 사용자)

1
GET http://localhost:4000/users/1

위와 같이 users 자원에서 id가 1인 사용자에 대한 자원을 GET하게 되면 다음과 같이 id가 1인 사용자에 대한 정보를 가져올 수 있다.

1
2
3
4
5
{
"id": 1,
"name": "Ro",
"country": "Korea"
}

이것을 코드로 작성하면 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
var req = new XMLHttpRequest();
req.open('GET', 'http://localhost:4000/users/1');
req.send();

req.onreadystatechange = function (e) {
if (req.readyState === XMLHttpRequest.DONE) {
if(req.status === 200) {
console.log(req.responseText);
} else {
console.log("Error!");
}
}
};


2. POST

users 자원에 새로운 사용자의 정보를 생성한다.

1
2
3
POST http://localhost:4000/users
"Content-Type: application/json"
'{"name": "donald", "country": "United States"}'

새로운 사용자의 정보를 생성하기 위해서는 payload가 필요하며, 위와 같이 Content-Type 등을 추가로 작성해야 한다.

1
2
3
4
5
{
"name": "donald",
"country": "United States",
"id": 5
}

이것을 코드로 작성하면 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var req = new XMLHttpRequest();
req.open('POST', 'http://localhost:4000/users');
req.setRequestHeader('Content-type', 'application/json');
req.send(JSON.stringify({
name: "donald",
country: "United States"
}));

req.onreadystatechange = function (e) {
if (req.readyState === XMLHttpRequest.DONE) {
if(req.status === 201) {
console.log(req.responseText);
} else {
console.log("Error!");
}
}
};


3. PUT

users 자원에서 새로 추가된 name을 jack으로 변경한다.

1
2
3
PUT http://localhost:4000/users/5
"Content-Type: application/json"
'{"name": "jack", "country": "United States"}'

PUT은 특정 id에 대한 어떤 정보를 변경할 때, payload에 모든 정보를 포함해서 보내준다.

1
2
3
4
5
{
"name": "jack",
"country": "United States",
"id": 5
}

이것을 코드로 작성하면 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var req = new XMLHttpRequest();
req.open('PUT', 'http://localhost:4000/users/5');
req.setRequestHeader('Content-type', 'application/json');
req.send(JSON.stringify({
name: 'jack',
country: "United States"
}));

req.onreadystatechange = function (e) {
if (req.readyState === XMLHttpRequest.DONE) {
if(req.status === 200) {
console.log(req.responseText);
} else {
console.log("Error!");
}
}
};


4. DELETE

users 자원에서 id가 5인 사용자를 삭제한다.

1
DELETE http://localhost:4000/users/5

사용자의 id까지 포함해서 DELETE 해야한다.

1
{}

이것을 코드로 작성하면 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
var req = new XMLHttpRequest();
req.open('DELETE', 'http://localhost:4000/users/5');
req.send();

req.onreadystatechange = function (e) {
if (req.readyState === XMLHttpRequest.DONE) {
if(req.status === 200) {
console.log(req.responseText);
} else {
console.log("Error!");
}
}
};