Search
▪️

Working with REST APIs - The Basics

What are REST APIs and why do we use Them?

모든 Frontend 사용자가 HTML Page로만 Interact하고, 서버에게서 HTML만 생성받는 것을 원하는 것은 아니다.
예를 들어서, Mobile Application의 경우에는 Server에서 HTML Code를 Render해달라고 할 Templating Language가 필요하지 않다. 해당 Application을 구현할 수 있도록 만들어진 Framework에서 사용하는 Code를 통해서 Interface를 구현하기 때문에 Server에서 HTML을 받는 것과는 별개의 얘기라는 것이다.
즉, 해당 Interface를 구현하게 되었을 때, Interface에 채워질 데이터만 있으면 되는 것이다. (Interface는 HTML Code가 아니라 자체 라이브러리 등을 이용해서 구현이 되기 때문이다.) 따라서 기존처럼 HTML Code를 받는 것보다 데이터를 받는 것이 더 낫다는 것이다.
또 다른 예로는 Single Page Web App을 이용하는 경우이다. 이런 Web Page 역시 Page Reloading 없이 그저 바뀌는 부분에 대해서만 Reredering을 수행하게 된다. 이런 케이스 역시 HTML을 Return 받는 것이 아니라, 바뀌는 데이터만을 받아서 나타내게 된다.
데이터만을 받는데, 전체 페이지를 Reloading하지 않아도 되는 이유는, 전체 Page가 Broswer단에서의 JavaScript로 Render되기 때문이다. (Browser 단에서의 JavaScript Code가 DOM을 조작할 수 있기 때문이다.) DOM은 이미 Render된 HTML Code이다.
즉, 보이는 Scene 뒤에서 데이터들만 바뀌게 되는 것이고, 이 바뀐 데이터들로 새로운 Page를 Load하지 않고도 부분만 바꾸어 나타낼 수 있는 것이다.
** Browser단에서의 JavaScript를 활용하는 유명한 Framework들은 React, Angular, Vue등이 있다.
위와 같은 두 케이스에 대해서도 REST API가 필요하긴 하지만, 꼭 Frontend에 보여줄 데이터들을 가져오려고만 REST API를 쓰는 것은 아니다. Third Party에서 사용하는 Service API를 이용하기 위해서도 REST API를 쓰기도 한다. 이렇게 Service API를 이용하는 경우에도 Server로 부터 HTML Page를 받기 원하는 것이 아니라 데이터를 받기를 원하는 것이다.
즉, REST API는 Frontend를 Backend와 서로 묶어서 작업하는 것이 아니라, 필요한 데이터들만 주고 받으면서 Frontend와 Backend를 별도로 분리하여 작업하게 하려는 것에 의의가 있다. (이렇게 Server가 데이터만을 제공하는 것이 REST API의 핵심 아이디어이다.)
REST API라고 함은, Representational State Transfer를 의미한다. 이 말은, Transfer Data instead of User Interfaces이다.
그렇다면 HTML Page를 Render하도록 하는 Server는 좋지 않은 Server인 것인가? → 실제로 그렇게 나쁜 것도 아니고, 많은 Web Application이 이미 이와 같이 쓸 정도로 흔한 Pattern이다. 하지만 Frontend와 Backend를 Decoupled하여 사용하고 싶은 다른 Application에 대해서는 REST API가 Solution이다.
REST API를 이용하는 Server와 기존 Server가 다른 것은 Response에 대한 것만 다를 뿐이지, General한 Server Side 로직이 다른 것은 아니다.

Accessing Data with REST APIs

Client는 Mobile App이거나 Single Page Application이라고 하고, Server가 있다고 하자. 여기서 Server에서는 App Backend에서 작용하는 API를 구현해둔다.
이렇게 Server에 API를 구현했을 때 장점은, 하나의 요청에도 처리가 가능할 뿐 아니라 여러 사용자들의 같은 API 요청에도 처리가 가능하다는 것이다. 이것이 장점으로 작용하는 이유는, Web과 Mobile을 동시에 구현한다고 했을 때, 두 Application은 동일한 데이터를 쓰기 때문에 하나의 API로도 두 Application을 모두 처리할 수 있기 때문이다.
Client와 Server가 동작할 때, 서로 주고 받는 것들은 바로 데이터이다! (오로지 데이터이고, 사용자의 User Interface를 주고 받지는 않는다.)
그렇다면 어떤 형식으로 데이터를 주고 받아야 하는가? → JSON 형식! (어떤 API를 쓰더라도 가장 보편적인 데이터 형식이다.)
1.
HTML
<p>Node.js</p>
Data + Structure
Contains User Interface
Unnecessarily difficult to parse if you just need the data
2.
Plain Text
Node.js
Data
No UI Assumptions
Unnecessarily difficult to parse, no clear data structure
3.
XML (HTML은 XML의 특별한 형태라고 보면 된다.)
<name>Node.js</name>
Data
No UI Assumptions
Machine-Readable but relatively verbose; XML-parser needed
4.
JSON
{"title" : "Node.js"}
Data
No UI Assupmtions
Machine-Readable and concise; Can easily be converted to JavaScript

Understanding Routing & HTTP Methods

REST API를 쓰는 경우에는 Client와 Server가 Communicate는 어떻게 하고, Routing은 어떻게 하는가? (Server에는 Server단의 로직이 있고, 데이터베이스에 대한 접근이 있다고 한다.)
이전에는 Client가 Server에게 Request를 보내려고 하면, Link를 추가하거나 HTML Page를 추가함으로써 혹은 Form의 Button을 눌러서 Form의 Action을 수행하도록 하면서 Request를 보낼 수 있었다.
REST API 역시, 기존의 이 틀과 크게 다르지는 않다. REST API 역시 HTTP Method를 통해서 Request를 보내게 된다. 조금 더 자세히 말하면, Server에 Request를 보낼 Method와 Path를 조합하여 Request를 보내게 된다. 이런 Request들은 Browser에서 수행하는 사용자의 Asynchronous JavaScript에 의해서 전달되게 되고 이렇게 전달된 Method/Path의 조합을 API Endpoint라고 한다.
우리가 해야할 일은, Request가 위와 같은 API Endpoint에 도달하였을 때 Server가 수행할 로직을 작성하는 것이다.
이렇게 REST API에서 수행되는 HTTP Methods(HTTP Verbs)는 GET, POST, PUT, PATCH, DELTE등이 있다. (기존의 방법대로 Browser와 작업하는 HTTP 방식은 GET, POST만 가능했었다. 이 두가지 Method들이 Browser가 유일하게 Native하게 알고 있는 Method기 때문이다.)
1.
GET
Get a Resource from the Server
2.
POST
Post a Resource to the Server (i.e. create or append Resource)
3.
PUT
Put a Resource onto the Server (i.e. create or overwrite a Resource)
4.
PATCH
Update parts of an existing Resource on the Server
5.
DELETE
Delete a Resource on the Server
6.
As an Option.. Determine whether follow-up Request is allowed (sent automatically)

REST APIs- The Core Principles

위에서 언급한 HTTP Method들은 어떤 방법을 어떻게 사용하여도 무방하다. 즉, POST를 통해서 Create만 하는 것이 아닌 Update를 해도, Delete를 하여도 무방하다. Method를 사용하는 것은 정의하기 나름이기 때문이다. 하지만 이와 관련하여 REST API를 쓰더라도 권장되는 원칙들이 있다.
1.
Uniform Interface
Clearly defined API endpoints with clearly defined request + response data structure
즉, API EndPoint만 보더라도 Predictable 해야 한다.
2.
Stateless Interactions
Server and client don't store any connection history, every request is handled separately
즉, 어느 곳에도 Connection History가 저장되지 않고, Session이 이용되지 않는다. 따라서 매번 새로 들어오는 Request들은 No Prior Request로 간주된다.
Client를 위한 Session을 별도로 저장하지 않기 때문에, Server는 모든 Request를 그냥 평범한 Request 그 자체로 본다. (이를 통해서 Frontend와 Backend의 Strong Decoupling이 가능한 것이다.)
따라서 Authorization에 대해서 Solution이 필요하다.
3.
Cachable
Servers may set caching headers to allow the client to cache responses
4.
Client-Server
Server and client are separated, client is not concerned with persistent data storage
5.
Layered System
Server may forward request to other APIs
6.
Code on Demand
Executable code may be transferred from server to client

Sending Requests & Responses and Working with Postman

REST API를 통해서 Request를 처리하고 Response를 내보내게 되면, Response에 대한 Status Code 처리는 더욱 중요해진다. HTML Page를 Return하는 것이 아니기 때문에 별도의 Error Page를 내보내지 않는다. 즉, 이런 것들에 대한 예외 처리를 Render하기 위해서는 Response를 기반으로 하여 UI를 Render해야 하고, Response 기반이라는 것이 곧 Status Code를 이용한다는 것이라고 할 수 있다.
Status Code를 받으면, Normal 한 UI를 Render 해야 할지, Error Interface를 Render해야 할지 Browser의 DOM을 제어함으로써 처리할 수 있다.

REST APIs, Client & CORS Errors

CORS라고 함은 Cross-Origin Resource Sharing이라고 한다. 이는 기본적으로 Browser에서는 허용되지 않는다.
이전에Request를 보내고 Response를 받는 작업에 아무런 문제 없이 원하는 대로 진행할 수 있었던 이유는 Client와 Server가 같은 Domain에서 구동되고 있었기 때문이다. (여기서의 Domain은 포트도 포함된다.)
즉, HTML File들을 Server에서 Render 했었고, Request를 처리하는 것 역시 HTML File들이 Render되는 것과 같은 Server에서 처리했었던 것이다.
하지만 위와 달리 Client와 Server가 서로 다른 Domain에서 구동되게 되면, Security Mechanism에 의해 CORS Error가 발생하게 된다. CORS Error을 Catch하는 Security Mechanism은 Browser에 의해서 제공되는 Mechanism이고, 이 Mechanism에 의해서 서로 다른 Domain, 서로 다른 Server, 서로 다른 Origin에 대해서 Resource Share가 불가능 한 것이다. (즉, 서로 다른 Domain 간에는 접근 불가한 것이다.)
위와 같이 Resource Share에 문제를 겪고 있는 것은 우리 Server의 데이터를 Share하게 Allow함으로써 해결 가능하다. (CORS Error를 잡는 Security Mechanism의 경우 서로 다른 Domain간 Share가 불가능 한 설정을 Overwrite 하여 해당 설정을 풀 수 있다. 특히 REST API를 이용하는 경우에 말이다.)
** 즉, 우리가 구현한 REST API를 우리 Domain에서만 사용할 것이 아니라 외부에서도 사용하게 허용할 수 있는 것이다. 구동되고 있는 Server와 같은 Domain을 가진 Client가 아니더라도 말이다. 예를 들면, Google Map API의 경우에는 Google 자사만이 해당 API를 쓰는 것이 아니다. API를 구동하고 있는 Server와 우리 Server의 Domain이 다름에도, 우리 Server에서도 Google API를 구동하게 할 수 있듯이 말이다. 또한 Frontend와 Backend를 구분하여 구동하고 싶은 경우에도 해당이 되겠다.
해결하는 방법은 Browser에게 우리 Server에서 보내는 Response에 대해서는 받아달라고 하는 것이다.
이 Response를 받아달라고 말하는 것은 무엇을 의미하는가? → 우리 Server단의 Code를 수정해야 한다.
Server에서 특정 Header에 대해서 설정이 필요하다. 특정 Header란, 우리 Server가 구동되는 범위를 벗어난 Response에 대한 Header이다. 이런 Header에 대한 설정은 app.js에 app.use() Middleware를 두면서 설정하는 것이 가장 좋다. (최종적으로 Response를 보내는 Route 이전에 두는 것이 좋다.)
Middleware에 setHeader() Method를 통해서 Header를 설정하고, 이를 통해서 Server가 구동되는 범위를 벗어나도 괜찮다고 말하는 것이다. (resopnse.json(), response.render()는 response를 보내는 것이지만, response.setHeader()는 response를 보내는 Packet의 Header만 정의할 뿐 response를 보내진 않는다.) 어느 Origin에서 접속을 허용할지, 해당 Origin에서 어떤 Methods들을 허용할지, 어떤 Header에 대해서 허용할지 (Header 설정의 두 번째 인자가 없다면 Default Header에 대해서만 적용된다.) 아래와 같이 설정한다.
response.setHeader('Access-Control-Allow-Origin', '$accessURL') response.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE') response.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization')
** 실제로 많은 사람들이 CORS Error를 Browser에서 구동되고 있는 JavaScript Code에서 해결을 하려고 하지만 이는 불가능하다. CORS Error에 대해서 접근을 허용하는 것은 Server에서만 해결이 가능하다.
** Header 설정에서 허용되는 Header를 예시와 같이 정하게 되면, Extra Authorization이 되어 있고 Request의 Content-Type이 정해져 있는 경우에만 허용한다는 것이다.
** Post시 Content-Type 잘 확인해야 한다. text/plain이 아니라 JSON을 처리할 수 있는 Type이어야 한다. 따라서 Browser에서 JSON 타입으로 Server에 보낼 수 있게 Stringify해야 하고, 해당 데이터가 application/json임을 Header에 명시해줘야 한다. 이 모든 과정은 fetch() Method 내에서 Option으로 설정 가능하다.
** Server에서 작성한 API를 Browser의 JavaScript Code를 통해서 Fetch할 수 있었는데, Ajax, Axios와 같은 Asynchronous Request들이 있다.