CS 상식/네트워크

REST API 정확하게 이해하고 개발하자

SparkIT 2024. 10. 30. 16:19

백엔드 개발은 굉장히 단순하게 표현하면 'REST API 만들기'라고 할 수 있습니다. 그리고 REST API를 단순하게 표현하면 '웹 상에서 클라이언트 요청에 응답하는 서버 기능'이라고 할 수 있죠.

그럼 이때 요청에 대한 응답을 해주는 코드만 짜면 REST API를 만들었다고 할 수 있을까요? 오늘은 REST API에 대한 더 자세한 정보들을 통해 무엇이 REST API인지, REST API 종류와 그 특징들에 어떤 것들이 있는지 함께 알아보겠습니다.

 


REST API(Representational State Transfer)란?

참고 영상 : NAVER D2: 그런 REST API로 괜찮은가

 

 REST API : 웹 상에서 HTTP 프로토콜을 통해 데이터를 주고받는 API로 REST 규칙을 따른다.

위는 제가 간단하게 정의해 본 REST API 내용입니다. 이때 REST란 무엇일까요?

위 영상을 보시면 알 수 있듯이 REST 개념을 만든 로이 필딩은 REST를 분산 하이퍼미디어 시스템을 위한 제약조건의 집합이라고 정의했습니다. 이 제약조건 집합에는 아래와 같은 조건들이 존재합니다.

 

 


REST 특징 6 가지

  1. 균일한 인터페이스
    일관적인 인터페이스로 분리되어야 합니다. 인터페이스 원칙은 다음과 같습니다.
    - 자원의 식별
    - 메시지를 통한 리소스의 조작
    - 자기서술적 메시지
    - 애플리케이션의 상태에 대한 엔진으로서 하이퍼미디어
  2. 클라이언트-서버 분리
    클라이언트와 서버 애플리케이션은 완전히 독립적이어야 합니다. 클라이언트 애플리케이션은 유일하게 리소스의 URI를 통해서만 서버 애플리케이션과 통신할 수 있습니다. 또한 서버 애플리케이션은 HTTP를 통해 요청된 데이터에 대한 응답을 클라이언트 애플리케이션에 하는 것 외에는 클라이언트 애플리케이션을 수정할 수 없습니다.
  3. 무상태
    상태 정보를 유지하지 않습니다. 즉, 각 요청에는 처리에 필요한 모든 정보가 포함되어야 합니다.
  4. 캐시 가능성
    클라이언트나 서버 측에 리소스를 캐시할 수 있어야 합니다.
  5. 계층화된 시스템 아키텍처
    서버는 다중 계층으로 구성될 수 있으며 보안, 로드 밸런싱, 암호화 계층을 추가해 구조상의 유연성을 둘 수 있고 PROXY, 게이트웨이 같은 네트워크 기반의 중간매체를 사용할 수도 있습니다.
  6. code-on-demand (optional)
    서버에서 클라이언트로 코드를 보내서 실행할 수 있어야 합니다.(javascript)

 

❗️참고사항(위 유튜브 링크에서 설명된 내용)
사실 요즘 사람들이 rest api라고 부르며 개발하는 api들은 정확한 정의에 따르면 restful 하지 않기 때문에 rest api라고 부르지 못한다고 합니다. 그 이유는 위 특징 중 1번 '균일한 인터페이스 성질'을 만족하지 않는 경우가 많기 때문인데요. 보통 2 가지 특징을 만족하지 못하는 경우가 많다고 합니다.

  • 자기서술적 메시지(self-descriptive message)
    rest api 요청의 목적지(Host)가 안 쓰여있거나 Content-Type이 "application/json"인 경우 해당 key값이 무엇을 의미하는지 명세가 포함되어있지 않은 경우 self-descriptive 하지 않으므로 rest api 조건을 만족하지 못합니다.
  • 애플리케이션의 상태에 대한 엔진으로서 하이퍼미디어(HATEOS)
    rest api 요청에 link에 대한 정보가 없으면 HATEOS 하지 않으므로 rest api 조건을 만족하지 않습니다.

즉, self-descriptive와 HATEOS 두 가지 모두 만족하기 위해서는 일반적으로 많이 사용되는 rest api들을 다음과 같이 수정해줘야 합니다.

# Self-descriptive 만족시키기
# 1. IANA에 내 json 파일에 대한 명세(미디어 타입)를 넣어둠. 그리고 해당 Media type을 사용한다는 것을 Content-Type을 통해 알려줌.
GET /todos HTTP/1.1
Host: example.org

HTTP/1.1 200 OK
Content-Type: application/vnd.todos+json
{
    "id":1, title="회사 가기",
    "id":2, title="집에 가기",
}


# 2. 내 json 파일에 대한 명세를 특정 url에 넣어두고 해당 url을 Link 헤더에 profile relation을 통해 알려줌.
GET /todos HTTP/1.1
Host: example.org

HTTP/1.1 200 OK
Content-Type: application/json
Link: <https://example.org/docs/todos>; rel="profile"
{
    "id":1, title="회사 가기",
    "id":2, title="집에 가기",
}

rest api에 대한 명세를 포함해야 합니다. 이때 사용 가능한 방법 중 하나가 바로 Link 헤더에 포함하는 것.

# HATEOS 만족시키기
# 1. json 데이터에 link 넣기
GET /todos HTTP/1.1
Host: example.org

HTTP/1.1 200 OK
Content-Type: application/json
Link: <https://example.org/docs/todos>; rel="profile"
{
    {
        "link": "https://example.org/todos/1",
        "title": "회사 가기"
    },
    {
        "link": "https://example.org/todos/2",
        "title": "집에 가기"
    }
}

클라이언트가 서버 자원 구조를 탐색하는데 도움을 줘야 합니다. 이때도 Link 헤더를 이용해 구조를 알려줄 수 있음.

 

이러한 이유로 로이 필딩은 위 조건들을 만족하지 못하는 API를 REST API가 아닌 다른 용어(ex: HTTP API)로 불러달라 부탁하고 있습니다.

 


REST API 메서드 종류

  1. GET
    서버로부터 데이터를 가져옵니다. 예시: 블로그 글 목록을 조회하는 경우 GET /posts를 사용합니다.
  2. POST
    서버에 새로운 데이터를 추가하거나 작성합니다. 예시: 새로운 댓글을 작성하는 경우 POST /comments를 사용합니다.
  3. PUT
    서버의 데이터를 갱신하거나 수정합니다. 이때 갱신되거나 수정되는 값은 데이터 전체에 해당됨. 또한 원하는 위치에 대한 데이터가 있으면 수정. 없으면 추가. 예시: 사용자 정보를 모두 업데이트하는 경우 PUT /users/1을 사용합니다. 이때 보통 path variable로 들어간 1이라는 값은 users 테이블의 기본 키(pk)를 의미합니다. 즉, 1번 pk 값의 데이터를 수정하겠다는 뜻. 이때 1번 pk에 해당하는 값이 없다면 pk값이 1번인 새로운 데이터를 추가합니다. 그리고 해당 메서드를 통해 수정을 하려고 하면 수정하고 싶은 내용을 본문에 넣어서 보내게 되는데, 이때 전체 데이터를 모두 보내야 한다. 만약 내가 바꾸고 싶은 데이터의 일부 정보만 본문에 넣어서 보내면 해당 부분은 수정이 되지만 나머지 데이터는 빈 값으로 대체된다. 즉, 유지하고 싶은 부분의 데이터도 그대로 작성해서 본문에 넣어줘야 함.
  4. PATCH
    리소스의 일부분을 수정합니다. 이때 단순 수정할 값을 넘겨주는 방식이 아니라 기존 값에 +10을 해라 이런 식으로도 이용이 가능합니다. 예시: 사용자 정보를 일부 업데이트하는 경우 PATCH /users/1을 사용합니다. 요청 본문에 내가 수정하고 싶은 일부의 정보만 넣어도 됩니다. 그럼 해당 부분만 변경됩니다.
  5. DELETE
    서버의 데이터를 삭제합니다. 예시: 게시물을 삭제하는 경우 DELETE /posts/42를 사용합니다.
  6. HEAD
    서버 리소스의 헤더 (메타 데이터)를 취득합니다.
  7. OPTIONS
    리소스가 지원하는 메서드의 목록을 취득합니다.

 

참고 자료 : 

 

HTTP - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. HTTP(HyperText Transfer Protocol, 문화어: 초본문전송규약, 하이퍼본문전송규약)는 W3 상에서 정보를 주고받을 수 있는 프로토콜이다. 주로 HTML 문서를 주고받는 데에

ko.wikipedia.org

HTTP 메소드 RFC 요청에 Body가 있음 응답에 Body가 있음 안전 멱등(Idempotent) 캐시 가능
GET RFC 9110 선택 사항
HEAD RFC 9110 선택 사항 아니요
POST RFC 9110 아니요 아니요
PUT RFC 9110 아니요 아니요
DELETE RFC 9110 선택 사항 아니요 아니요
CONNECT RFC 9110 선택 사항 아니요 아니요 아니요
OPTIONS RFC 9110 선택 사항 아니요
TRACE RFC 9110 아니요 아니요
PATCH RFC 5789 아니요 아니요 아니요

위 테이블에서 안전, 멱등 컬럼에 대한 추가 설명

  • 안전
    위 자료를 통해 get 메서드는 안전하지만, 다른 post, put, delete, patch 메서드는 안전하지 않다고 한다. 이 이유는 get은 단순 조회이므로 서버에 문제를 발생시킬 여지가 적지만 다른 메서드들은 서버 상태를 변경하거나 리소스를 추가하거나 수정 혹은 삭제하므로 주의가 필요하다는 뜻이다.
  • 멱등
    멱등이란 연속한 요청을 보냈을 때 동일한 결괏값을 얻을 수 있는지다. 이때 결괏값이란 요청에 의한 응답을 의미하는 것이 아니다. 리소스의 상태를 의미한다. 즉, 1번 실행했을 때와 2번 실행했을 때 동일한 상태를 만들 수 있냐를 묻는 것이다.
    • get : o
      get 요청 1번 보냈을 때 : 데이터베이스 데이터 중 a라는 값 조회
      get 요청 2번 보냈을 때 : 데이터베이스 데이터 중 a라는 값 조회 (똑같은 조회니까 달라지는 거 없음)
    • post : x
      post 요청 1번 보냈을 때 : 데이터베이스 데이터 중 a라는 값 추가
      post 요청 2번 보냈을 때 : 데이터베이스 데이터 중 a라는 값 또 추가 (1번 요청했을 때보다 a라는 값이 1개 더 많아진다)
    • put : o
      put 요청 1번 보냈을 때 : 데이터베이스 데이터 중 a라는 값 b로 수정
      put 요청 2번 보냈을 때 : 데이터베이스 데이터 중 b라는 값 b로 수정 (위에서 이미 b로 수정되었긴 하지만 그래도 또 b로 수정. 하지만 결과는 동일하다)
    • patch : x
      patch 요청 1번 보냈을 때 : 데이터베이스 데이터 중 a라는 값 b로 수정
      patch 요청 2번 보냈을 때 : 데이터베이스 데이터 중 b라는 값 b로 수정 (이런 경우에는 멱등함)

      patch 요청 1번 보냈을 때 : 데이터베이스 데이터 중 a라는 값 +10. –> a=10
      patch 요청 2번 보냈을 때 : 데이터베이스 데이터 중 a라는 값 +10. –> a=20 (이런 경우에는 멱등하지 않음)
    • delete : o
      delete 요청 1번 보냈을 때 : 데이터베이스 데이터 중 a라는 값 삭제
      delete 요청 2번 보냈을 때 : 데이터베이스 데이터 중 a라는 값은 없으므로 삭제하지 못함 (하지만 결과는 동일하게 a라는 값이 삭제된 상태. 이때 delete는 없는 값을 삭제하려 했기 때문에 오류 코드를 반환한다. 가끔 여기서 위에서는 완벽하게 a를 삭제했다는 메시지를 반환받고 아래에서는 오류 코드를 반환하니 반환하는 값이 달라 멱등하지 않지 않은 것 아니냐는 식으로 이해하는 경우가 많다. 하지만 위에서 말했듯 반환값이 같은지를 따져서 멱등한지를 확인하는 것이 아닌 서버의 상태나 리소스의 상태가 동일한지 따져서 멱등한지를 구분하기 때문에 이 경우는 동일하게 a 데이터가 삭제된 상태이므로 멱등하다고 하는 것)