REST vs REST API vs RESTful API 무엇이 다른걸까? (+HTTP method)

DH.J·2024년 10월 30일
1

Javascript

목록 보기
6/8
post-thumbnail

What you will learn

  • REST, REST API, RESTful 비교
  • REST 원칙을 지켜야 하는 이유
  • REST API 설계 규칙
  • HTTP method(GET, POST, PUT, PATCH, DELETE)

💁 What is REST API?

REST API는 REST(Representational state transfer) 기반으로 만들어진 API입니다.
REST는 HTTP의 장접을 최대한 활용할 수 있는 아키텍처이고, 자원을 이름으로 구분하여 해당 자원의 상태를 주고받는 모든 것을 의미합니다.

REST의 원칙을 지킨 서비스 디자인을 RESTful이라고 표현합니다.

RESTful API는 REST를 기반으로 데이터를 ‘웹 URL’을 통해 API를 일관성 있게 사용가능하게 하는 인터페이스입니다. 이를 통해 개발자들이 일관성있게 API를 만들고 이용하는 것을 도와줍니다.

그렇다면 REST의 원칙을 왜 지켜야 하는 것일까?

Scalability

REST API를 실행시키는 시스템은 효율적으로 확장이 가능합니다.
서버와 클라이언트의 상호작용을 최적화하기 때문입니다. (잘 관리되는 캐싱으로 클라이언트-서버 통신 단축 등)
이러한 특징들이 퍼포먼스를 향상시킬 수 있습니다.

Flexibility

RESTful 웹 서비스는 클라이언트와 서버의 분리를 가능하게 한다
다양한 서버 구성 요소를 단순화하고 분리하여 각 부분이 독립적으로 발전할 수 있도록 합니다

Independence

API 설계에 영향을 주지 않고 다양한 프로그래밍 언어로 클라이언트 및 서버 애플리케이션을 모두 작성할 수 있습니다.

REST의 구성요소는 무엇일까?

  1. Resource : 자원 (URI)
  2. Verb : 자원에 대한 행위 (HTTP method)
  3. Representations : 자원에 대한 행위의 구체적 내용 (payload)

REST 아키텍쳐 스타일 6가지 원칙

1. uniform interface

일관된 인터페이스를 사용하기 위해선 몇가지 규약들이 필요합니다.
그리고 리소스는 single URL을 통해 식별 가능하도록 유일해야 합니다.

2. Client-server based

일관된 인터페이스는 데이터 스토리지로부터 유저를 분리시킵니다.
클라이언트의 도메인은 UI와 request 수집에 관한 것이고,서버의 도메인은 데이터 액세스, 워크로드 관리, 보안에 관한 것입니다.
클라이언트와 서버를 분리하면 각각을 서로 독립적으로 개발하고 개선할 수 있습니다.

3. Stateless

클라이언트에서 서버로 보내는 요청에는 서버가 이를 이해하고 적절히 처리할 수 있도록 필요한 모든 정보가 포함되어야 합니다. 서버는 클라이언트 상태에 대한 어떠한 정보도 가지고 있을 수 없습니다.

4. caching

요청에 대한 응답 내의 데이터는 캐시 가능 또는 캐시 불가능으로 레이블이 지정되어야 합니다.

5. Layered system

REST는 계층적 구조를 허용함으로써, 각 컴포넌트들은 상호작용할 때 바로 위 계층 너머를 볼 수 없습니다.

6. Code on demand

REST API는 스크립트 형태로 코드를 다운로드하고 실행합니다.
서버는 XML 또는 JSON 형태로 데이터를 보내는데, 이는 서버가 필요할 때 실행 가능한 코드를 클라이언트로 보낼 수 있게 합니다.


💁 REST API 설계 원칙

1. URI는 리소스를 표현하는 데 집중하기

동사보다는 명사를, 대문자보다는 소문자를 사용합시다.
따라서 이름에 get 같이 행위에 대한 표현이 들어가면 안됩니다.

# ❌ bad
GET /getTodos/1 
GET /todos/show/1

# ✅ good
GET /todos/1
DELETE /todos/2

2. 행위에 대한 정의는 HTTP method를 통해 하기

HTTP 요청 메서드는 클라이언트가 서버에게 요청의 종류와 목적을 알리는 방법입니다.
주로 get, post, put patch, delete를 사용해서 CRUD(Create, Replace, Update, Delete) 를 구현합니다.

  • GET : 리소스를 조회(retrieve)
  • POST : 데이터 추가, 등록(create)
  • PUT : 리소스 대체 / 해당 리소스가 없으면 새롭게 생성(replace)
  • DELETE : 리소스 삭제(delete)
  • PATCH : 리소스 부분 변경(modify)

3. 나머지 규칙들

  • 슬래시 구분자(/ )는 계층 관계를 나타내는데 사용한다.
    ex) http://restapi.example.com/houses/apartments
  • URI 마지막 문자로 슬래시(/ )를 포함하지 않는다.
    • URI에 포함되는 모든 글자는 리소스의 유일한 식별자로 사용되어야 하며 URI가 다르다는 것은 리소스가 다르다는 것이고, 역으로 리소스가 다르면 URI도 달라져야 한다.
    • REST API는 분명한 URI를 만들어 통신을 해야 하기 때문에 혼동을 주지 않도록 URI 경로의 마지막에는 슬래시(/)를 사용하지 않는다.
      ex) http://restapi.example.com/houses/apartments/ (X)
  • 하이픈(- )은 URI 가독성을 높이는데 사용
    • 불가피하게 긴 URI경로를 사용하게 된다면 하이픈을 사용해 가독성을 높인다.
  • 밑줄(_ )은 URI에 사용하지 않는다.
    • 밑줄은 보기 어렵거나 밑줄 때문에 문자가 가려지기도 하므로 가독성을 위해 밑줄은 사용하지 않는다.
  • URI 경로에는 소문자가 적합하다.
    • URI 경로에 대문자 사용은 피하도록 한다.
  • 파일확장자는 URI에 포함하지 않는다.
    • REST API에서는 메시지 바디 내용의 포맷을 나타내기 위한 파일 확장자를 URI 안에 포함시키지 않는다.
    • Accept header를 사용한다.
      ex) http://restapi.example.com/members/soccer/345/photo.jpg (X)
      ex) GET / members/soccer/345/photo HTTP/1.1 Host: restapi.example.com Accept: image/jpg (O)
  • 리소스 간에는 연관 관계가 있는 경우
    • /리소스명/리소스 ID/관계가 있는 다른 리소스명
      ex) GET : /users/{userid}/devices (일반적으로 소유 ‘has’의 관계를 표현할 때)

💁 JSON server를 이용한 REST API

1. GET

Read & Retrieve 할 때 사용합니다.
만약에 GET요청이 성공적으로 이루어진다면 XML이나 JSON과 함께 200 (Ok) 응답 코드를 리턴합니다.
error가 발생하면 주로 404 (Not found) 또는 400 (Bad request) 발생합니다.

데이터를 조회하는 것이기 때문에 요청시에 Body 값과 Content-Type 값이 비워져있습니다.
GET은 캐싱이 가능하여 같은 데이터를 한번 더 조회할 경우에 저장한 값을 사용하여 조회 속도가 빨라집니다.

const xhr = new XMLHttpRequest();
// ✅ GET: get todos
xhr.open('GET', 'https://jsonplaceholder.typicode.com/todos/1');
// HTTP 요청
xhr.send();

xhr.onload = () => {
    if (xhr.status === 200) {
        document.querySelector('div').textContent = xhr.response;
    } else {
        console.log('Error', xhr.status, xhr.statusText);
    }
}

2. POST

새로운 리소스를 create할 때 사용됩니다.
성공적으로 완료하면 201 (Created) 응답을 반환합니다.
URL을 통해서 데이터를 받지 않고, Body 값을 통해서 받습니다.

이때, 데이터를 생성하는 것이기 때문에 요청시에 Body 값과 Content-Type 값을 작성해야합니다.

body : {date : "example"}
Content-Type : "application/json"

⚠️ POST 요청은 idempotent 하지 않습니다.
같은 POST 요청을 반복해서 했을 때 항상 같은 결과물이 나오는 것을 보장하지 않는다!

const xhr = new XMLHttpRequest();

// ✅ POST: create new todo 
xhr.open('POST', 'https://jsonplaceholder.typicode.com/todos/1/posts');

// payload의 MIME type 지정
xhr.setRequestHeader('content-type', 'application/json');

// HTTP request 
// send payload to server
xhr.send(JSON.stringify({ title: "New Title!", completed: false}));

xhr.onload = () => {
    if (xhr.status === 200 || xhr.status === 201) {
        document.querySelector('div').textContent = xhr.response;
    } else {
        console.log('Error', xhr.status, xhr.statusText);
    }
}

3. PUT

id를 제외한 특정 리소스 전체를 업데이트하기 위해 사용합니다.
데이터를 수정하는 것이기 때문에 요청시에 Body 값과 Content-Type을 함께 보내야 합니다.

⚠️ PUT 요청은 idempotent 합니다.
요청할 때마다 데이터를 생성하는 POST와는 다르게, 동일한 PUT 요청을 여러 번 호출하면 항상 동일한 결과가 생성됩니다.

const xhr = new XMLHttpRequest();
// ✅ id: 1 리소스로 요소를 특정합니다
xhr.open('PUT', 'https://jsonplaceholder.typicode.com/posts/1');

xhr.setRequestHeader('content-type', 'application/json');

xhr.send(JSON.stringify({ userId: 3, title: "New Title!", completed: false}));

xhr.onload = () => {
    if (xhr.status === 200) {
        document.querySelector('div').innerHTML = xhr.response;
    } else {
        console.log('Error', xhr.status, xhr.statusText);
    }
}

// HTTP request
xhr.send(JSON.stringify({ userId: 3, id: 3, title: "New Title!", body: "hello world!"}));

server로 보낼 object의 key-value 부분만 바꿔서 request 해 보았다.

이렇게 모든 값 전체가 교체되지만 id는 바뀌지 않는 것을 볼 수 있습니다.
왜냐하면 처음에 id로 todo를 특정하여 리소스 전체를 교체했기 때문입니다.

4. PATCH

전체를 업데이트하는 PUT과는 다르게, 특정 리소스의 일부를 수정할 때 사용합니다.
예를 들어 todo의 completed 부분만 true -> false 바꿀 때 유용합니다.
데이터를 수정하는 것이기 때문에 요청시에 Body 값과 Content-Type을 함께 보내야 합니다.

⚠️ POST 요청은 idempotent 하지 않습니다.

const xhr = new XMLHttpRequest();
// ✅ id: 1 리소스로 요소를 특정합니다
xhr.open('PUT', 'https://jsonplaceholder.typicode.com/posts/1');

xhr.setRequestHeader('content-type', 'application/json');

xhr.send(JSON.stringify({ completed: false }));

xhr.onload = () => {
    if (xhr.status === 200) {
        document.querySelector('div').innerHTML = xhr.response;
    } else {
        console.log('Error', xhr.status, xhr.statusText);
    }
}

5. DELETE

리소스에서 id를 사용하여 특정 요소를 삭제합니다.
데이터를 삭제하는 것이기 때문에 요청시에 Body 값과 Content-Type 값이 비워져있습니다.

URL을 통해서 어떠한 데이터를 삭제할지 parameter를 받습니다.
데이터 삭제에 성공한다면 Body 값 없이 성공 응답만 보내게 됩니다.

const xhr = new XMLHttpRequest();
// ✅ id: 1인 todo를 삭제합니다.
xhr.open('DELETE', 'https://jsonplaceholder.typicode.com/posts/1');

xhr.send();

xhr.onload = () => {
    if (xhr.status === 200) {
        document.querySelector('div').innerHTML = xhr.response;
    } else {
        console.log('Error', xhr.status, xhr.statusText);
    }
}

Reference

  1. https://khj93.tistory.com/entry/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-REST-API%EB%9E%80-REST-RESTful%EC%9D%B4%EB%9E%80
  2. https://blog.postman.com/rest-api-examples/
  3. https://aws.amazon.com/ko/what-is/restful-api/
  4. https://hahahoho5915.tistory.com/54
  5. https://velog.io/@yh20studio/CS-Http-Method-%EB%9E%80-GET-POST-PUT-DELETE
profile
평생 질문하며 살고 싶습니다.

0개의 댓글