|
| 1 | +### Chapter 44 - REST API |
| 2 | + |
| 3 | +REST는 HTTP를 기반으로 클라이언트가 서버의 리소스에 접근하는 방식을 규정한 아키텍처이고 |
| 4 | +REST API는 REST를 기반으로 서비스 API를 구현한 것을 의미한다. |
| 5 | + |
| 6 | +<br> |
| 7 | + |
| 8 | +### REST API의 구성 |
| 9 | + |
| 10 | +REST API는 자원, 행위, 표현 3가지 요소로 구성된다. |
| 11 | + |
| 12 | +- 자원: URI |
| 13 | +- 행위: HTTP 요청 메서드 |
| 14 | +- 표현: 페이로드 |
| 15 | + |
| 16 | +<br><br> |
| 17 | + |
| 18 | +### REST API 설계 원칙 |
| 19 | +REST에서 가장 중요한 기본 원칙은 2가지이다. |
| 20 | +- URI는 리소스를 표현하는데 집중한다. |
| 21 | +- 행위에 대한 정의는 HTTP 요청 메소드를 통한다. |
| 22 | + |
| 23 | +<br> |
| 24 | + |
| 25 | +#### URI는 리소스를 표현하는데 집중한다. |
| 26 | +URI는 리소스를 표현하는 데 중점을 두어야 한다. |
| 27 | +리소스를 식별할 수 있는 이름은 동사보다는 명사를 사용한다. |
| 28 | +``` text |
| 29 | +GET /todos/1 |
| 30 | +GET /users/1 |
| 31 | +``` |
| 32 | + |
| 33 | +<br> |
| 34 | + |
| 35 | +#### 행위에 대한 정의는 HTTP 요청 메소드를 통한다. |
| 36 | +HTTP 요청 메서드는 클라이언트가 서버에게 요청의 종류와 목적을 알리는 수단이다. |
| 37 | +주로 5가지 요청 메소드(GET, POST, PUT, PATCH, DELETE)를 사용하여 CRUD를 구현한다. |
| 38 | + |
| 39 | +| 요청 메서드 | 종류 | |
| 40 | +|:---:|:---:| |
| 41 | +|GET|리소스 조회| |
| 42 | +|POST|리소스 생성| |
| 43 | +|PUT|리소스 전체 변경| |
| 44 | +|PATCH|리소스 부분 변경| |
| 45 | +|DELETE|리소스 삭제| |
| 46 | + |
| 47 | +<br> |
| 48 | + |
| 49 | +리소스에 대한 행위는 HTTP 요청 메소드를 통해 표현한다. |
| 50 | + |
| 51 | +``` text |
| 52 | +DELETE /todos/1 |
| 53 | +``` |
| 54 | + |
| 55 | +<br><br> |
| 56 | + |
| 57 | +### JSON Server를 이용한 REST API 실습 |
| 58 | + |
| 59 | +#### JSON Server 설치 |
| 60 | + |
| 61 | +``` bash |
| 62 | +$ mkdir json-server-exam && cd json-server-exam |
| 63 | +$ npm init -y |
| 64 | +$ npm install json-server --save-dev |
| 65 | +``` |
| 66 | + |
| 67 | +<br> |
| 68 | + |
| 69 | +#### db.json 파일 생성 |
| 70 | +프로젝트 루트 폴더(/json-server-exam)에 db.json 파일을 생성한다. |
| 71 | +db.json 파일은 리소스를 제공하는 데이터베이스 역할을 한다. |
| 72 | + |
| 73 | +``` json |
| 74 | +{ |
| 75 | + "todos": [ |
| 76 | + { "id": 1, "content": "HTML", "completed": false }, |
| 77 | + { "id": 2, "content": "CSS", "completed": true }, |
| 78 | + { "id": 3, "content": "JavaScript", "completed": false } |
| 79 | + ] |
| 80 | +} |
| 81 | +``` |
| 82 | + |
| 83 | +<br> |
| 84 | + |
| 85 | +#### JSON Server 실행 |
| 86 | +JSON Server를 실행한다. |
| 87 | +JSON Server가 데이터베이스 역할을 하는 db.json 파일의 변경을 감지하게 하려면 `watch` 옵션을 추가한다. |
| 88 | + |
| 89 | +``` bash |
| 90 | +$ json-server --watch db.json --port 4000 |
| 91 | +``` |
| 92 | + |
| 93 | +<br> |
| 94 | + |
| 95 | +매번 명령어 입력하는 것이 번거롭다면 `package.json` 파일의 scripts를 아래와 같이 수정하여 JSON Server를 실행하면 된다. |
| 96 | + |
| 97 | +``` json |
| 98 | +{ |
| 99 | + "name": "json-server-exam", |
| 100 | + "version": "1.0.0", |
| 101 | + "scripts": { |
| 102 | + "start": "json-server --watch db.json --port 4000" |
| 103 | + }, |
| 104 | + "devDependencies": { |
| 105 | + "json-server": "^0.17.0" |
| 106 | + } |
| 107 | +} |
| 108 | +``` |
| 109 | + |
| 110 | +<br> |
| 111 | + |
| 112 | +터미널에서 `npm start` 명령어를 실행하면 JSON Server가 실행된다. |
| 113 | +``` bash |
| 114 | +$ npm start |
| 115 | +``` |
| 116 | + |
| 117 | +<br><br> |
| 118 | + |
| 119 | +#### GET 요청 |
| 120 | +JSON Server의 루트 폴더(/json-server-exam)에 `public` 폴더를 생성하고 그 안에 `get_index.html` 파일을 생성한다. |
| 121 | +이후 서버를 종료 후 재시작하자. |
| 122 | + |
| 123 | +`todos` 리소스에서 모든 todo를 취득한다. |
| 124 | + |
| 125 | +``` html |
| 126 | +<!DOCTYPE html> |
| 127 | +<html> |
| 128 | +<body> |
| 129 | + <pre></pre> |
| 130 | + <script> |
| 131 | + const xhr = new XMLHttpRequest(); |
| 132 | + xhr.open('GET', '/todos'); |
| 133 | + xhr.send(); |
| 134 | +
|
| 135 | + xhr.onload = () => { |
| 136 | + if (xhr.status === 200) { |
| 137 | + document.querySelector('pre').textContent = xhr.response; |
| 138 | + } else { |
| 139 | + console.error('Error', xhr.status, xhr.statusText); |
| 140 | + } |
| 141 | + } |
| 142 | + </script> |
| 143 | +</body> |
| 144 | +</html> |
| 145 | +``` |
| 146 | + |
| 147 | +<br> |
| 148 | + |
| 149 | +`todos` 리소스에서 id를 사용하여 특정 `todo`를 취득(retrieve)해보자. |
| 150 | +public 폴더에 `get_retrieve.html`을 추가해보자. |
| 151 | + |
| 152 | +`todo` 리소스에서 특정 todo를 취득한다. |
| 153 | + |
| 154 | +``` html |
| 155 | +<!DOCTYPE html> |
| 156 | +<html> |
| 157 | +<body> |
| 158 | + <pre></pre> |
| 159 | + <script> |
| 160 | + const xhr = new XMLHttpRequest(); |
| 161 | + xhr.open('GET', '/todos/1'); |
| 162 | + xhr.send(); |
| 163 | +
|
| 164 | + xhr.onload = () => { |
| 165 | + if (xhr.status === 200) { |
| 166 | + document.querySelector('pre').textContent = xhr.response; |
| 167 | + } else { |
| 168 | + console.error('Error', xhr.status, xhr.statusText); |
| 169 | + } |
| 170 | + } |
| 171 | + </script> |
| 172 | +</body> |
| 173 | +</html> |
| 174 | +``` |
| 175 | + |
| 176 | +<br><br> |
| 177 | + |
| 178 | +#### POST 요청 |
| 179 | +public 폴더에 `post.html` 파일을 추가해보자. |
| 180 | + |
| 181 | +todo 리소스에 새로운 todo를 생성한다. |
| 182 | +POST 요청 시에는 `setRequestHeader` 메소드를 사용하여 요청 몸체에 담아 서버로 전송할 페이로드의 MIME 타입을 지정해야 한다. |
| 183 | + |
| 184 | +``` html |
| 185 | +<!DOCTYPE html> |
| 186 | +<html> |
| 187 | +<body> |
| 188 | + <pre></pre> |
| 189 | + <script> |
| 190 | + const xhr = new XMLHttpRequest(); |
| 191 | + xhr.open('POST', '/todos'); |
| 192 | + |
| 193 | + // 요청 몸체에 담아 서버로 전송할 페이로드의 MIME 타입을 지정 |
| 194 | + xhr.setRequestHeader('Content-type', 'application/json'); |
| 195 | + |
| 196 | + // HTTP 요청 전송 |
| 197 | + // 요청 몸체에 담아 서버로 전송할 페이로드를 인수로 전달 |
| 198 | + xhr.send(JSON.stringify({ |
| 199 | + id: 4, |
| 200 | + content: 'Angular', |
| 201 | + completed: false |
| 202 | + })); |
| 203 | +
|
| 204 | + xhr.onload = () => { |
| 205 | + // 응답 상태 코드가 200(OK) 또는 201(Created)인 경우 정상 처리된 것으로 판단 |
| 206 | + if (xhr.status === 200 || xhr.status === 201) { |
| 207 | + document.querySelector('pre').textContent = xhr.response; |
| 208 | + } else { |
| 209 | + console.error('Error', xhr.status, xhr.statusText); |
| 210 | + } |
| 211 | + } |
| 212 | + </script> |
| 213 | +</body> |
| 214 | +</html> |
| 215 | +``` |
| 216 | + |
| 217 | +<br><br> |
| 218 | + |
| 219 | +#### PUT 요청 |
| 220 | +`PUT`은 특정 리소스 전체를 교체할 때 사용한다. |
| 221 | +PUT 요청 시에는 `setRequestHeader` 메소드를 사용하여 요청 몸체에 담아 서버로 전송할 페이로드의 MIME 타입을 지정해야 한다. |
| 222 | + |
| 223 | +``` html |
| 224 | +<!DOCTYPE html> |
| 225 | +<html> |
| 226 | +<body> |
| 227 | + <pre></pre> |
| 228 | + <script> |
| 229 | + const xhr = new XMLHttpRequest(); |
| 230 | +
|
| 231 | + // todos 리소스에서 id가 1인 리소스 전체를 교체 |
| 232 | + xhr.open('PUT', '/todos/4'); |
| 233 | + |
| 234 | + xhr.setRequestHeader('Content-type', 'application/json'); |
| 235 | +
|
| 236 | + xhr.send(JSON.stringify({ |
| 237 | + id: 4, |
| 238 | + content: 'TypeScript', |
| 239 | + completed: false |
| 240 | + })); |
| 241 | +
|
| 242 | + // 요청이 완료되었을 경우 발생하는 이벤트 핸들러 |
| 243 | + xhr.onload = () => { |
| 244 | + if (xhr.status === 200 || xhr.status === 201) { |
| 245 | + document.querySelector('pre').textContent = xhr.response; |
| 246 | + } else { |
| 247 | + console.error('Error', xhr.status, xhr.statusText); |
| 248 | + } |
| 249 | + } |
| 250 | + </script> |
| 251 | +</body> |
| 252 | +</html> |
| 253 | +``` |
| 254 | + |
| 255 | +<br> |
| 256 | + |
| 257 | +#### PATCH 요청 |
| 258 | +`PATCH`는 특정 리소스 일부를 변경할 때 사용한다. |
| 259 | +PATCH 요청 시에는 `setRequestHeader` 메소드를 사용하여 요청 몸체에 담아 서버로 전송할 페이로드의 MIME 타입을 지정해야 한다. |
| 260 | + |
| 261 | +``` html |
| 262 | +<!DOCTYPE html> |
| 263 | +<html> |
| 264 | +<body> |
| 265 | + <pre></pre> |
| 266 | + <script> |
| 267 | + const xhr = new XMLHttpRequest(); |
| 268 | + xhr.open('PATCH', '/todos/4'); |
| 269 | + |
| 270 | + xhr.setRequestHeader('Content-type', 'application/json'); |
| 271 | +
|
| 272 | + xhr.send(JSON.stringify({ |
| 273 | + content: 'TypeScript', |
| 274 | + completed: false |
| 275 | + })); |
| 276 | + |
| 277 | + // 요청이 완료되었을 경우 발생하는 이벤트 핸들러 |
| 278 | + xhr.onload = () => { |
| 279 | + if (xhr.status === 200 || xhr.status === 201) { |
| 280 | + document.querySelector('pre').textContent = xhr.response; |
| 281 | + } else { |
| 282 | + console.error('Error', xhr.status, xhr.statusText); |
| 283 | + } |
| 284 | + } |
| 285 | + </script> |
| 286 | +</body> |
| 287 | +</html> |
| 288 | +``` |
| 289 | + |
| 290 | + |
| 291 | +<br><br> |
| 292 | + |
| 293 | +#### DELETE 요청 |
| 294 | +`DELETE`는 특정 리소스를 삭제할 때 사용한다. |
| 295 | +DELETE 요청 시에는 `setRequestHeader` 메소드를 사용하여 요청 몸체에 담아 서버로 전송할 페이로드의 MIME 타입을 지정해야 한다. |
| 296 | + |
| 297 | +``` html |
| 298 | +<!DOCTYPE html> |
| 299 | +<html> |
| 300 | +<body> |
| 301 | + <pre></pre> |
| 302 | + <script> |
| 303 | + const xhr = new XMLHttpRequest(); |
| 304 | + xhr.open('DELETE', '/todos/4'); |
| 305 | + |
| 306 | + xhr.send(); |
| 307 | +
|
| 308 | + xhr.onload = () => { |
| 309 | + if (xhr.status === 200 || xhr.status === 201) { |
| 310 | + document.querySelector('pre').textContent = xhr.response; |
| 311 | + } else { |
| 312 | + console.error('Error', xhr.status, xhr.statusText); |
| 313 | + } |
| 314 | + } |
| 315 | + </script> |
| 316 | +</body> |
| 317 | +</html> |
| 318 | +``` |
| 319 | + |
0 commit comments