Project/[약올림] Final Project

[프로젝트 기획 및 준비작업] API를 좀 더 RESTful 하게

HJChung 2021. 1. 22. 08:57

프론트엔드와 백엔드가 소통하는 엔드포인트, RESTful API

꼭 정독해보자!!!!

 

 


 

아래는 약 4달전에 commonJS와 RESTful API에 대해 처음 배웠을 때 정리한 글이다.

21. Server & Node - CommonJS/RESTful API

 

REST API를 쓴다고 정해놓고 RESTful 하게 디자인하는 것의 중요성을 많이 들어왔음에도 불구하고 솔직히 말하면 'RESTful'한게 대체 뭔지도 모르고 그냥 '써왔다.'

 

그러다가 어제 office hour시간에 아니나 다를까 API디자인에 대해 많은 피드백을 받았다.

우선

1. 한 API에 기능이 2개가 겹쳐있다는 것이었고

(예를 들어, 검색/삭제 기능이 순차적으로 이루어져야 할 때, 검색을 위한 API, 삭제를 위한 API로 나눈 것이 아니라 한 API에 검색/삭제 기능이 모두 들어가게 짠 것이다.)

2. resource와 URI를 표현하는 방식조차 이상

(이렇게 쓰는 개발자는 없어요 라는 식)

하다는 것이었다.

 

그래서 이제는 더이상 REST API를 RESTful하게 디자인 하는 것을 배우고 실천하는 것을 미룰 수 없다는 판단하에, 코드 작업이 조금 미뤄지더라도 API 수정을 하기로 했다.

(1차 프로젝트를 해본 결과 초반 SR작업을 꼼꼼히 하지 않으면 언젠간 같은 문제로 터져버린다. 빠르게 모래성을 쌓을 것인가 시간이 조금 걸리더라도 단닫한 기반을 갖출것인가 에 대한 질문에 우리 팀의 판단은 후자이다!)

 

우선 REST API가 무엇인지에 대해 다시 정리해보았다.


1. REST API란

1) API는 뭐고 JSON은 뭔지

Client는 요청하는 주체이며, API가 이 요청/응답을 정리해서 상호작용 매개역할을 하고, Server는 응답하는 주체이다. Client와 Server는 HTTP라고 하는 규약, 규칙(Protocol)을 지켜서 통신한다.

이때 하나의 앱에 다양한 기능이 추가될수록 클라이언트와 서버의 상호작용이 많아지게 될 것이다.

그런데 다~ 다른 언어로 다른 방식으로 대화한다면? 24시간 내내 사람이 요청을 해석해줘야 할지도 모른다.

그래서 클라이언트와 서버가 대화하는 규칙을 만들었다. 

 

"앞으로 서버와 클라이언트가 대화할 때는 [서버야/이 동작을/여기에 해줘] 처럼 하자"라는 규칙!

이런 대화의 규칙이 API이고 이 메세지의 포맷을 JSON(단 반드시 이렇게 응답해야 한다고 규정한 것은 아니다. JSON을 써도 되고, XML을 써도 된다.)이라 한다.

서버에게 어떻게 요청을 보낼지에 대한 API를 잘 알아야하며 같은 API라 하더라도 리소스마다 서로 다른 API 규칙을 가진다.

출처: https://brunch.co.kr/@businessinsight/65

2) 그럼 REST API는 뭐지

앞선 내용처럼 서버와 클라이언트의 대화의 규칙이 API일때, 너무나 다양한 스타일의 API가 있으면 그때마다 각각에 대해 다시 공부하기엔 큰 어려움이 아닐 수 없다. 그래서 필요한 게! REST API이다. 

전 세계 개발자들이 통일한 API를REST API라고 한다.

출처:  https://brunch.co.kr/@businessinsight/65

즉, client와 server의 통신 시에 어떻게하면 시행착오를 줄이고 더 좋은 API를 만들 수 있을까에 대한 고민의 결과가 REST API이다.

2. REST API는 어떻게 디자인 하는가?

이를 위해서는 먼저 Resource부터 시작해 여러 개념들을 이해하는 것이 매우 중요하다.

1) Resource? 

Roy Fielding은 Resource를 'REST에서 정보의 가장 핵심적인 추상화는 리소스이다. 이름 붙일 수 있는 정보면 어떤 것이든 리소스가 될 수 있다.'고 정리했다.

Server가 Resource(정보)를 주면 이를 어떻게 조작하고, 일관되게 표현할 것인가가 핵심 이다.

예를 들어, 하나하나의 글을 topic이라고 한다면 이를 DB 테이블에 저장했을 때의 형태는

이렇게 될 것이다. 이 전체를 Resource라고 할 수 있다.

 

 

 

2) Resource를 REST API로 표현한다면?

2-1) Resource 표현 및 식별 

Resource를 REST API로 나타낸다면 URI를 통해 표현된다.

 

https://restfulapi.net/resource-naming/ 에는 resource를 어떻게 표현할 것인가에 대한 가이드라인을 주고있다. <더보기> 클릭!

더보기
  • 리소스를 나타내는데 명사를 사용하라
  • 일관성이 핵심이다.
  • CRUD 기능 이름은 URI에 사용하지 마라
  • filter가 필요하면 query component를 사용하라
 

1. topic 전체 또는 여러개를 식별하고자 할 때 URI - Collection

2. topic 중 한 건을 식별하고자 할 때 URI - Element 

 

하지만 URI는 Resource 식별 할 뿐이고, 이 식별된 Resource를 가공하려면 어떻게 해야할까??

 

2-2)Resource 가공 및 활용

Resource의 가공 및 활용 형태가 바로 REST API에서 method라고 불리는 Create(생성), Read(읽기), Update(수정), Delete(삭제)이다.

 

그리고 HTTP 통신규약을 이용하는 REST API에서는 이 CRUD작업을 하기 위해서 HTTP가 가지는 method를 이용한다.

이렇게 HTTP 각 메서드를 본래의 용도에 맞게 사용하자는 것도 중요한 목표로 여기기 때문이다.

  • Create(생성) - HTTP의 POST 메서드
  • Read(읽기) - HTTP의 GET 메서드
  • Update(수정) - 전체 내용을 수정하는 HTTP의 PUT 메서드, 부분적인 내용을 수정하는 HTTP의 PATCH 메서드
  • Delete(삭제) - HTTP의 DELETE 메서드

3. 직접 REST API를 디자인하여서 예시 데이터(Resource) 를 가공 및 활용(CRUD) 해보자. 

예시 데이터 (resource)

ex 1. topic resource에 문서 하나 더 생성하고 싶은 경우

아래와 같은 코드로 작성될 수 있다.

주목할 것은 URI에 '/topics' 로 resource의 식별자를 사용하고, '생성'하고자 하는 것이므로 HTTP method의 'POST'를 메서드로 사용한다는 것.

fetch('topics', {
    method:'POST', 
    headers:{'content-type':'application/json'},
    body:JSON.stringify({
        title:'fetch', body:'fetch is ...'
    })
})
    .then(
        function(response){
            console.log('status', response.status);
            return response.json()
        }
    )
    .then(
        function(result){
            console.log(result);
        }
    )

즉 여기서 알 수 있는 RESTful API의 핵심은 '데이터의 resource는 URI로 식별하고, 원하는 행위는 적절한 method를 사용하는 것' 으로, HTTP POST /topics 가 됨으로써 아래의 RESTful한 API 조건을 만족한다.

  • CRUD 기능 이름은 URI에 사용하지 마라

그러면 이에 대한 요청의 응답이 어떻게 왔는지 볼까?

이렇게 HTTP의 응답코드를 정확하게 사용하는 것을 통해서 결과를 알려준다.

즉, 핵심은 HTTP의 응답코드를 정확하게 사용하는 것으로 RESTful한 API 조건을 만족한다.

만약 에러가 발생했을 때도 적절한 상황에 맞는 HTTP의 응답코드와 함께 필요한 메세지를 응답해야 한다.

HTTP/1.1 400 Bad Request
{
"msg" : "check your parameter"
}

※ HTTP의 응답코드에 대한 가이드는 RESTful API 설계 가이드의 <5. Use HTTP status>와 <6. Use the correct HTTP status code.>에서 잘 설명되어 있다.

 

ex 2. topics resource data 전체를 읽어오고 싶은 경우 - collection 읽기

fetch('topics', {method:'GET'})
.then(
    function(response){
        return response.json()
    }
)
.then(
    function(result){
        console.log(result);
    }
)

즉 핵심은'데이터의 resource는URI로 식별하고, 원하는 행위는 적절한 method를 사용하는 것'으로,HTTP GET /topics가 됨으로써 아래의 RESTful한 API 조건을 만족한다.

 

ex 3. topics resource 중 특정 한 건을 읽어오고 싶은 경우 - element 읽기

fetch('topics/2')
.then(
    function(response){
        return response.json()
    }
)
.then(
    function(result){
        console.log(result);
    }
)

즉 핵심은'데이터의 collection resource / 뒤에 해당 element의 식별자를 넣음으로써 URI로 식별하고, 원하는 행위는 적절한 method를 사용하는 것'으로,

HTTP GET /topics/2가 됨으로써 아래의 RESTful한 API 조건을 만족한다.

 

※ 그럼 Path Variable과 Query Parameter를 각각 언제 사용해야 하는가? 만약 어떤resource를 식별하고 싶으면Path Variable을 사용하고, 정렬이나 필터링을 한다면Query Parameter를 사용하는 것이 Best Practice이다.

관련된 내용은 <[번역] Path Variable과 Query Parameter는 언제 사용해야 할까?> 에 잘 나와있다.

 

ex 4. topics resource 중 부분을 수정하고 싶은 경우 - PATCH의 사용

fetch('topics/2', {
    method:'PATCH', 
    headers:{'content-type':'application/json'},
    body:JSON.stringify({
        title:'fetch - patch'
    })
})
    .then(
        function(response){
            return response.json()
        }
    )
    .then(
        function(result){
            console.log(result);
        }
    )

body에 요청시에 작성한 것만 수정이 이루어지고, 나머지에는 영향이 가질 않는다.

ex 5. topics resource 중 전체를 수정하고 싶은 경우 - PUT의 사용

fetch('topics/2', {
    method:'PUT', 
    headers:{'content-type':'application/json'},
    body:JSON.stringify({
        title:'fetch - put'
    })
})
    .then(
        function(response){
            return response.json()
        }
    )
    .then(
        function(result){
            console.log(result);
        }
    )

body에 요청시에 작성한 것만 반영되고 작성하지 않은 데이터는 완저 삭제된다.

4. 관계를 가지는 Resource들은 URI에 어떻게 표현하여 식별 할 수 있을까?

부모가 되는 것을 앞에 쓰고/ 그 부모 element의 id값을 적고/그것에 종속된 resource식별자(자식이 되는 것)을 쓴다. 

fetch('topics/1/comments', {
    method:'GET'
})
    .then(
        function(response){
            return response.json()
        }
    )
    .then(
        function(result){
            console.log(result);
        }
    )

 

 

지금까지 REST API와 간단하게나마 RESTful 한 디자인에 대해서 알아보고 정리해 보았다. 

본문 중에 링크를 걸어놓은 많은 글들과 생활코딩의 <기계들의 대화법 - REST API>을 주로 참고하였다. 

 

현재 어제 피드백을 받고 나서 진행중인 프로젝트의 API 수정 작업은 

https://www.notion.so/API-dc75c203e6164d1e8b4e3a1dff852174

 

약올림 API

POST ID find

www.notion.so

에서 하고 있으며 (이 API로 한다는게 아니라 팀원들이 각자 고민하고 만들어 본 뒤 수요일 팀미팅 시간에 논의 후 확정하기로 하였다. )

위의 정리한 내용을 바탕으로 수요일 전까지 좀 더 REST API에 가까운 API를 디자인 해볼 것이다!

 

끝.