REST 서버, REST API란?

Kim Ju Hui·2020년 3월 21일
10

K-POP 역사관

목록 보기
2/3

node.js에서 express.js로 프로젝트를 진행하면서 REST 서버를 구축하고, REST API를 만들었다고 하긴 하는데 그게 정확히 뭐인지 모른 상태로 얼렁뚱땅 지나가다가 결심이 선 김에 공부해보면서 정리해본다.

REST란 무엇인가?

REST는 Representational State Transfer를 의미한다. 뭐래

한국인이니 한글로 풀어서 말을 하자면 자원을 이름(자원의 표현)으로 구분하여 해당 자원의 상태(정보)를 주고 받는 모든 것을 의미한다고 한다.

자원은 해당 소프트웨어가 관리하는 모든 것을 의미하며, 뭐 예를 들면 DB 안에 들어가 있는 데이터 하나하나, 이미지 하나하나 등을 의미할 수 있겠다. 상태의 전달은 데이터가 요청되어지는 시점에서 요청받은 자원의 상태(정보)를 전달하는것을 의미하는데, 보통 JSON 형태나 XML 형태를 이용하여 자원의 상태를 전달하게 된다.

(하도 JSON을 써서 그런지 JSON이 편하다. 사실 XML 안 써봐서 그렇다)

REST의 구체적인 개념은 HTTP URL을 통해 자원을 명시하고, HTTP Method(POST, GET, DELETE, PUT)를 통해 해당 자원에 대한 CRUD(CREATE, READ, UPDATE, DELETE) 오퍼레이션을 적용하는 것이라고 할 수 있다.

REST의 구성 요소

아까 REST의 의미가 자원을 이름으로 구분하여 해당 자원의 상태를 주고 받는 모든 것이라고 하였는데, 여기서 REST의 중요한 세 가지 구성 요소가 모두 나온다.

  1. 자원(Resource) : URL
    • 모든 자원에는 고유한 ID가 존재하게 되고, 이 자원은 Server에 존재한다.
    • 자원을 구별하는 ID는 HTTP URL로 구분하게 된다. (ex) /members/1
    • Client는 URL을 이용하여 자원을 지정하고 해당 자원에 대한 조작을 Server에 요청한다
  2. 행위(Verb) : HTTP Method
    • Client는 HTTP Method(POST, GET, DELETE, PUT)를 이용하여 지정한 자원에 대한 조작을 요청한다.
  3. 표현(Representation of Resource)
    • Client가 Server에 자원에 대한 조작을 요청하면 Server는 이에 대한 적절한 응답(Representation)을 보낸다.

REST의 특징

REST에는 다음과 같이 크게 6가지의 특징이 있다.

  1. Uniform (유니폼 인터페이스)

    Uniform Interface는 Client가 지정한 리소스에 대한 조작을 통일되고 한정적인 인터페이스로 수행하는 아키텍처 스타일을 의미한다.
    이 말이 무슨 말인고 하니, 먼저 한정적인 인터페이스가 무엇인지부터 알아보자.

    우리가 보통 흔히 보는 URL은 params를 이용하여 어떤 resource에 접근할 수 있었다. 예를 들어, (정말 예를 들어) 내 벨로그의 관리자 페이지에 접속하고자 한다면, params를 사용할 경우 velog.io/@kjh107704?auth=admin 이라는 URL로 접근할 수 있었다.
    하지만 한정적인 인터페이스를 사용한다면 굳이 params를 사용하지 않고 velog.io/@kjh107704/admin 이라는 URL로 간편하게 사용할 수 있다.

    params를 사용한 URLvelog.io/@kjh107704?auth=admin
    한정적인 인터페이스의 URLvelog.io/@kjh107704/admin

    여기까지만 보면 그래서 어쩌라는거지? 싶은데, 한정적인 인터페이스의 진가는 이 다음에 나온다고 생각한다.

    위의 예시에 이어서 관리자 홈페이지를 조회할 경우와 수정할 경우를 생각해 보자.

    params를 이용하여 URL을 구성할 경우, velog.io/@kjh107704?auth=admin 이 URL로 관리자 페이지 resource에는 접근하긴 했는데 얘를 어찌 할 것인지를 또 params로 넘겨주던가 해야 한다.

    이에 반해, 한정적인 인터페이스를 사용하면 HTTPS Method를 사용하면 되니까 관리자 페이지를 조회할 경우에는 GET velog.io/@kjh107704/admin, 수정할 경우에는 PUT velog.io/@kjh107704/admin과 같이 간편하게 나타낼 수 있다.

    이런 한정적인 인터페이스를 사용하게 되면 URL 길이가 짧아질 뿐만 아니라 하나의 URL을 이용하여 많은 representation을 할 수 있다는 장점이 있다.

  2. Stateless (무상태성)

    REST가 무상태성 성격을 갖는다는 말은 작업을 위한 상태정보를 별도로 저장하고, 관리하는 일을 하지 않는다는 것을 의미한다. 이러한 이유로 세션 정보나 쿠키 정보를 별도로 저장하고 있지 않기 때문에 서버는 들어오는 요청을 단순히 처리하기만 하면 된다. 따라서 서비스의 자유도가 높아지고, 서버에서 불필요한 정보를 관리하지 않기 때문에 구현이 단순해진다.

  3. Cacheable (캐시 가능)

    Cacheable은 REST의 가장 큰 특징 중 하나라고 한다. REST는 웹 표준인 HTTP를 그대로 사용하기 때문에, 웹에서 사용하는 기존 인프라를 그대로 사용할 수 있다. 따라서 HTTP가 가진 캐싱 기능을 적용할 수 있는데, HTTP 프로토콜 표준에서 사용하는 Last-Modified 태그나 E-Tag 등을 이용하면 쉽게 구현이 가능하다고 한다.

    근데 사실 웹을 최적화하면서 개발해 본 경험은 없어서 캐싱이 정확히 어떤 장점을 가져오는지는 아직 피부로..? 키보드로..? 느껴보지는 못했다.

  4. Self-descriptiveness (자체 표현 구조)

    Self-descriptiveness라는 것은 REST API만 보고도 이를 쉽게 이해할 수 있다는 것이다. 예를 들어, REST API가 다음과 같이 이루어졌을 때, velog.io/@kjh107704/product/food/salad 이것만 보고도 salad가 food 이며 product에 속한 것을 단번에 알 수 있다.

  5. Client - Server 구조

    REST 서버는 API 제공, Client는 사용자 인증이나 컨텍스트(세션, 로그인 정보)등을 직접 관리하는 구조로 되어있어 Server와 Client의 역할이 명확히 나뉘기 때문에 각 필드에서 개발해야할 점이 명확해지고 서로 간의 의존성이 줄어들게 된다.

  6. 계층형 구조

    REST 서버는 다중 계층으로 구성될 수 있으며, 보안, 로드 밸런싱, 암호화 계층 등을 추가해 구조상의 유연성을 둘 수 있고, PROXY, 게이트웨이와 같은 네트워크 기반의 중간매체를 사용할 수 있다.

REST API 디자인 가이드

REST API 설계 시 가장 중요한 항목은 두 가지이다.
1. URL은 정보의 자원을 표현해야 한다.
2. 자원에 대한 행위는 HTTP Method(GET, POST, PUT, DELETE)로 표현한다.

REST API 중심 규칙

  1. URL은 정보의 자원을 표현해야 한다.

    GET /members/delete/1

    위의 URL은 REST를 제대로 적용하지 않았다. URL은 정보의 자원을 표현하는데에 집중해야 하므로, delete와 같은 행위에 대한 표현이 들어가면 안된다.

    따라서, 리소스명은 동사보다는 명사를 사용하는 것이 좋다.

  2. 자원에 대한 행위는 HTTP Method(GET, POST, PUT, DELETE)로 표현한다.

    위의 잘못 된 URL을 HTTP Method를 통해 고쳐보면

    DELETE /members/1

    이라고 고칠 수 있다.

    HTTP Method를 통해 CRUD를 할 수 있다.
    |Method|CRUD 역할|
    |:----|:----|
    |POST|POST를 통해 해당 URL을 요청하면 리소스를 생성함|
    |GET|GET을 통해 해당 리소스를 조회한다. 리소스를 조회하고 해당 도큐먼트에 대한 자세한 정보를 가져온다|
    |PUT|PUT을 통해 해당 리소스를 수정한다.|
    |DELETE|DELETE를 통해 리소스를 삭제한다.|

REST API 설계 시 주의할 점

  1. 슬래시 구분자(/)는 계층 관계를 나타낼 때 사용한다.

    velog.io/@kjh107704/product/food/salad
  2. URL 마지막 문자로 슬래시(/)를 포함하지 않는다.

    URL에 포함되는 모든 글자는 리소스의 유일한 식별자로 사용되어야 한다. 이에 따라 URL이 다르다는 것은 리소스가 다르다는 것을 의미하며, 역으로 말하면 리소스가 다를 경우 URL이 달라야 함을 의미한다. REST API는 분명한 URL을 만들어 통신을 해야 하기 때문에 혼동을 주지 않도록 URL의 마지막 경로에는 슬래시(/)를 사용하지 않는다.

  3. 하이픈(-)은 URL 가독성을 높이는데 이용한다.

    불가피하게 긴 URL을 사용하게 된다면 하이픈(-)을 사용해 가독성을 높이는 것이 좋다.

  4. 밑줄(_)은 URL에 사용하지 않는다.

    글꼴에 따라 다르긴 하지만 밑줄은 보기 어렵거나 밑줄 때문에 다른 문자가 가려지기도 하므로 사용하지 않는것이 좋다.

  5. URL 경로에는 소문자가 적합하다.

    URL 경로에 대문자를 사용하게 될 경우, 대소문자에 따라 다른 리소스로 식별할 수도 있기 때문에 URL 경로는 소문자만을 이용해서 구성하는 것이 좋다. RFC 3986(URL 문법 형식)에서는 URL 스키마와 호스트를 제외하고는 대소문자를 구별하도록 규정하기 때문이다.

  6. 파일 확장자는 URL에 포함시키지 않는다.

    공부를 시작하면서 가장 신기하고 새롭게 알게 된 부분이다.

    REST API에서는 메세지 바디 내용의 포맷을 나타내기 위한 파일 확장자를 URL 안에 포함하지 않고, Accept header를 사용한다고 한다.

    http://restapi.example.com/members/soccer/345/photo.jpg (X)
    GET / members/soccer/345/photo HTTP/1.1 Host: restapi.example.com Accept: image/jpg (O)

    Accept 헤더가 무엇인고 하니, HTTP 요청에 대한 응답으로 받고 싶은 미디어타입(MIME 형식으로 표현되는)을 명시하는 헤더라고 한다. Accept 헤더와 같이 요청을 받은 서버는 클라이언트의 제안 중 하나를 선택하고 사용하여 Content-Type 응답 헤더로 클라이언트에게 선택된 미디어 타입에 대해 알려주게 된다.

    Accept 헤더의 문법은 다음과 같다.

    Accept: <MIME_type>/<MIME_subtype>
    Accept: <MIME_type>/*
    Accept: */*
    
    // Multiple types, weighted with the quality value syntax:
    Accept: text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8
    • <MIME_type>/<MIME_subtype>
      • text/html 타입과 같이 단일의 간결한 MIME 타입을 의미힌다.
    • <MIME_type>/*
      • 서버 타입을 갖지 않은 MIME 타입을 의미한다.
      • image/*image/png, image/gif, image/svg등 어떤 다른 이미지 타입들과도 일치한다.
    • */*
      • 모든 MIME 타입
    • ;q= (q-인자 가중치)
      • 사용되는 모든 값을 weight라고 부르는 상대적인 가중치를 이용하여 타입의 선호 순서를 표시한다.

리소스 간의 관계를 표현하는 방법

REST 리소스 간에는 연관 관계가 있을 수 있고, 이런 경우 다음과 같은 표현 방법을 사용한다. 만약 관계명이 복잡하다면 이를 서브 리소스에 명시적으로 표현하는 방법이 있다.

/리소스명/리소스 ID/관계가 있는 다른 리소스명

GET : /creatores/{creatorId}/products (일반적으로 소유 ‘has’의 관계를 표현할 때)
GET : /users/{userid}/likes/products (관계명이 애매하거나 구체적 표현이 필요할 때)

생각해보니 지난번 프로젝트때 아무 생각 없이 팀원들끼리 정해서 쓴 리소스 관계 표현 방법이 맞는 방법이었다. 역시 멈춘 시계도 하루에 두번은 맞는다...

자원을 표현하는 Collection과 Document

CollectionDocument는 모두 리소스이며 URL에 표시된다. 차이점을 말하자면 Document는 객체 하나 정도로 이해하면 되고, Collection은 객체의 집합 정도로 이해하면 된다.

예를 들어,

/creatores/1

위와 같은 URL에서는 creatores 컬렉션과 1(id가 1번인 creator)을 의미하는 도큐먼트로 URL이 구성된다고 생각하면 된다.

좀 더 예시를 보자면

/creatores/1/products/3

이런 URL에서는 creatores, products 컬렉션과 1(id가 1번인 creator), 3(id가 3번인 product)을 의미하는 도큐먼트로 URL이 구성된다고 생각하면 된다.

위의 예시 모두 예전 풀스택 프로젝트에서 썼던 URL로 기억하는데 나름 컬렉션과 도큐먼트를 잘 지켜서 사용했다는것에 놀라고 있는 중이다. 역시 고장난 시계!

여기서 중요한 점은 컬렉션은 복수로 사용했다는 점이다. 좀 더 직관적인 REST API를 위해서는 컬렉션과 도큐먼트를 사용할 때 복수/단수를 지켜준다면 좀 더 이해하기 쉬운 직관적인 URL을 설계할 수 있다.

HTTP 응답 상태 코드

사실 지난번에 플젝을 하면서 HTTP 응답 에러가 엄청 났었다. 잘 만든 페이지라면 응답 에러를 캐치하고 그것을 해결하는 코드가 있어야겠지만, 우린 잘 만든 페이지가 아니었다. 모든 응답이 에러가 없도록 FIX된 홈페이지 (큰그림)

앞으로 개발을 할 때에는 try-catch구문을 좀 잘 이용해 보고 싶다.

이런 마음을 담아 HTTP 응답 상태 코드를 정리해 보도록 하자.

상태코드
200클라이언트의 요청을 정상적으로 수행함
201클라이언트가 어떠한 리소스 생성을 요청, 해당 리소스가 성공적으로 생성됨(POST를 통한 리소스 생성 작업 시)
400클라이언트의 요청이 부적절한 경우 사용하는 응답 코드
401클라이언트가 인증되지 않은 상태에서 보호된 리소스를 요청했을 때 사용하는 응답 코드
(로그인 하지 않은 유저가 로그인 했을 때에만 요청 가능한 리소스를 요청했을 때)
403유저 인증상태와 관계 없이 응답하고 싶지 않은 리소스를 클라이언트가 요청했을 때 사용하는 응답 코드
(403 보다는 400이나 404를 사용할 것을 권고. 403 자체가 리소스가 존재한다는 뜻을 내포하기 때문임)
405클라이언트가 요청한 리소스에서는 사용 불가능한 Method를 이용했을 경우 사용하는 응답 코드
301클라이언트가 요청한 리소스에 대한 URL이 변경됐을 때 사용하는 응답 코드
(응답 시 Location header에 변경된 URL을 적어 줘야 함)
500서버에 문제가 있을 경우 사용하는 응답 코드

출처
https://programmer7895.tistory.com/28
https://meetup.toast.com/posts/92
https://gmlwjd9405.github.io/2018/09/21/rest-and-restful.html
https://spoqa.github.io/2013/06/11/more-restful-interface.html
https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Accept

profile
뻘짓을 많이 하는 꼬부기

1개의 댓글

comment-user-thumbnail
2023년 11월 26일

감사합니다.

답글 달기