๋“ค์–ด๊ฐ€๋ฉฐ

Self-Descriptive ๋ž€ ๋ง ๊ทธ๋Œ€๋กœ ๋ฉ”์‹œ์ง€๊ฐ€ ์Šค์Šค๋กœ ์„ค๋ช…์ด ๋˜์–ด์•ผ ํ•œ๋‹ค๋Š” ๋œป์ด๋‹ค. ์‘๋‹ต ๋ฉ”์‹œ์ง€์˜ ์š”์†Œ๋งŒ ๋ณด๊ณ  ๊ทธ ๋œป์„ ์•Œ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค. ๋งŒ์•ฝ ์„œ๋ฒ„์˜ API ๊ฐ€ ๋ณ€๊ฒฝ๋˜๊ฑฐ๋‚˜ URI ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋Š” ๋“ฑ ๊ธฐ๋Šฅ์ด ์ˆ˜์ •๋œ๋‹ค ํ•˜๋”๋ผ๋„ ํด๋ผ์ด์–ธํŠธ๋Š” ๋ฌธ์ œ ์—†์ด ๋Œ์•„๊ฐ€์•ผ ํ•œ๋‹ค. ์ด๋Ÿด ๋•Œ ์„œ๋กœ์„œ๋กœ Self-Descriptive messages ๋ฅผ ํ™œ์šฉํ•œ๋‹ค๋ฉด ๊ฐœ๋ฐœ์ž๊ฐ€ ์š”์ฒญ์˜ ์˜๋ฏธ๋ฅผ ์‰ฝ๊ฒŒ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์–ด ์ดํ•ด๋„๋ฅผ ๋†’์ผ ์ˆ˜ ์žˆ๋‹ค. ๊ฒฐ๋ก ์ ์œผ๋กœ REST API ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š”๋ฐ Self-Descriptive ๋Š” API ์˜ ์ดํ•ด๋„, ์œ ์ง€๋ณด์ˆ˜์„ฑ, ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์ด๋Š” ๋ฐ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•œ๋‹ค.

Self Descriptive

RESTful ์•„ํ‚คํ…์ฒ˜์˜ ์ œ์•ฝ์‚ฌํ•ญ ์ค‘ ํ•˜๋‚˜๋กœ, ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ถ”๊ฐ€์ ์ธ ๋ฌธ์„œ ์—†์ด๋„ ์‘๋‹ต ๋ฉ”์‹œ์ง€๋งŒ ๋ณด๊ณ  ๊ทธ ์˜๋ฏธ๋ฅผ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฐœ๋…์ด๋‹ค. ์•„๋ž˜ ๋ฐฉ๋ฒ•์œผ๋กœ ๋งŒ์กฑํ•  ์ˆ˜ ์žˆ๋‹ค.

  • โœ… HTTP ์ƒํƒœ ์ฝ”๋“œ ํ™œ์šฉ : ์ผ๋ฐ˜์ ์ธ ์›น ๊ฐœ๋ฐœ์„ ํ•œ๋‹ค๋ฉด ์ง€์ผœ์ง€๋Š” ๋‚ด์šฉ์ด๋‹ค.

  • โœ… Content-Type ๋ฐ Accept ํ—ค๋” ํ™œ์šฉ : Content-Type ์€ ์‘๋‹ตํ•  body ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ๋ถ™์—ฌ์ฃผ๋ฉด ๋œ๋‹ค.

HTTP/1.1 200 OK
Content-Type: application/json
[ { "id": "example123", "name": "ํ™๊ธธ๋™" } ]

์—ฌ๊ธฐ๊นŒ์ง€๋Š” ๋ฌธ์ œ๊ฐ€ ์—†๊ฒ ์ง€๋งŒโ€ฆ ์œ„ ์˜ˆ์‹œ๋ฅผ ์ž์„ธํžˆ ์‚ดํŽด๋ณด๋ฉด id, name ์ด ๋ฌด์—‡์„ ์˜๋ฏธํ•˜๋Š”๊ฐ€์— ๋Œ€ํ•œ ํ•ด์„ค์€ ์—†๋‹ค. ์ด ๊ฒฝ์šฐ Self Descriptive ์— ์œ„๋ฐฐ๋œ๋‹ค ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์•„๋ž˜ 3๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ์ƒ๊ฐํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค.


๋ฐฉ๋ฒ• 1. media-type ์ •์˜

IANA ์— ๋ฏธ๋””์–ด ํƒ€์ž…์„ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๋‹ค. id ๊ฐ€ ๋ฌด์—‡์ด๊ณ  name ์ด ๋ฌด์—‡์ธ์ง€ ์ •์˜ํ•˜์—ฌ ๋“ฑ๋กํ•˜๋ฉด ๋˜๊ณ , ์ด ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ›๋Š” ์‚ฌ๋žŒ์€ ๋ช…์„ธ๋ฅผ ์ฐพ์•„๊ฐˆ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์˜๋ฏธ๋ฅผ ์˜จ์ „ํžˆ ํ•ด์„ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋งค๋ฒˆ media type ์„ ์ •์˜ํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ๋น„ํšจ์œจ์ ์ด๋ผ ํ•  ์ˆ˜ ์žˆ๋‹ค โ€ฆ


๋ฐฉ๋ฒ• 2. profile ๋งํฌ ํ—ค๋”

id, name ์ด ๋ฌด์—‡์ธ์ง€ ์ •์˜ํ•œ ๋ฌธ์„œ๋ฅผ ์ž‘์„ฑํ•˜์—ฌ Link ํ—ค๋”์— profile relation ์œผ๋กœ ํ•ด๋‹น ๋ช…์„ธ๋ฅผ ๋งํฌํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค. ์ด ๊ฒฝ์šฐ ํด๋ผ์ด์–ธํŠธ๊ฐ€ Link ํ—ค๋”์™€ profile ์„ ์ดํ•ดํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ profile ๋งํฌ ํ—ค๋”๋Š” ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ํ•œ๋‹ค (!!!)


๋ฐฉ๋ฒ• 3. HAL ์˜ ๋งํฌ ๋ฐ์ดํ„ฐ์— profile ๋งํฌ ํ—ค๋” ์ถ”๊ฐ€

๋งค๋ฒˆ media type ์„ ์ •์˜ํ•˜๋Š” ๊ฒŒ ๋ฒˆ๊ฑฐ๋กญ๊ณ , profile ๋งํฌ ํ—ค๋”๋Š” ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ง€์›ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— HAL(Hypertext Application Language)์— ๋ช…์„ธ์˜ ๋งํฌ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ถ”์ฒœํ•œ๋‹ค. ์ด๋ฅผ HATEOAS ๋ผ๊ณ  ํ•˜๋Š”๋ฐโ€ฆ

HATEOAS (hypermedia as the engine of application state)

ํ˜„์žฌ์˜ URI ์—์„œ ๋‹ค์Œ์œผ๋กœ ์ „์ด๋  ์ˆ˜ ์žˆ๋Š” URI ๋ฅผ ํ‘œ์‹œํ•ด์ฃผ๋Š” ๊ฒƒ์„ ๋งํ•œ๋‹ค. ํด๋ผ์ด์–ธํŠธ๋ฅผ ๊ฐœ๋ฐœํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์ด ํŠน์ • ๋ฉ”์„œ๋“œ๋กœ๋ถ€ํ„ฐ ์˜ฌ ์ˆ˜ ์žˆ๋Š” ๊ฒฐ๊ณผ๋ฅผ ์˜ˆ์ธกํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•ด์ง€๊ณ , API ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋”๋ผ๋„ ๊ธฐ์กด์˜ ๋งํฌ๋ฅผ ํ†ตํ•ด ์ƒˆ๋กœ์šด ์—”๋“œํฌ์ธํŠธ๋ฅผ ์ฐพ์•„์„œ ์ž‘์—…์„ ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํด๋ผ์ด์–ธํŠธ ์ธก ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•  ์ผ์ด ์ ์–ด์ง„๋‹ค.


์˜ˆ์‹œ๋ฅผ ํ†ตํ•ด ์•Œ์•„๋ณด์ž.

< HTML ์˜ ๊ฒฝ์šฐ >

#์˜ˆ์‹œ
GET / todos HTTP/1.1
Host: example.org

HTTP/1.1 200 OK
Content-Type : text/html

<html>
<body>
<a href="https://todos/1"> ํšŒ์‚ฌ ๊ฐ€๊ธฐ</a>
<a href="https://todos/2"> ์ง‘์— ๊ฐ€๊ธฐ</a>
<body>
<html>
  • โœ… Self-Descriptive : ๋ชจ๋“  ํƒœ๊ทธ๋Š” ํ•ด์„ ๋ฐฉ๋ฒ•์„ ๊ตฌ์ฒด์ ์œผ๋กœ ์ฐพ์„ ์ˆ˜ ์žˆ๊ณ , ํžŒํŠธ๋งŒ์„ ๋‹จ์„œ๋กœ ํ•ด์„ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • โœ… HATEOAS : a ํƒœ๊ทธ๋ฅผ ํ†ตํ•ด ๋‹ค์Œ์œผ๋กœ ์ „์ด๋  ํŽ˜์ด์ง€๋ฅผ ๋ช…์‹œํ•จ.


< JSON ์˜ ๊ฒฝ์šฐ >

GET / todos HTTP/1.1
Host:L exampele.org

HTTP/1.1 200 OK
Content-Type: application/json
[
  {"id": 1, "title": "ํšŒ์‚ฌ ๊ฐ€๊ธฐ"},
  {"id": 2, "title": "์ง‘์— ๊ฐ€๊ธฐ"},
]
  • โŒ Self-Descriptive : id ๊ฐ€ ๋ฌด์—‡์„ ์˜๋ฏธํ•˜๋Š”์ง€, title ์ด ๋ฌด์—‡์„ ์˜๋ฏธํ•˜๋Š”์ง€ ์•Œ ๊ธธ์ด ์—†์Œ.

  • โŒ HATEOAS : ๋‹ค์Œ์œผ๋กœ ์ „์ด๋  ํŽ˜์ด์ง€๊ฐ€ ๋ฌด์—‡์ธ์ง€ ๋ช…์‹œ๋˜์–ด ์žˆ์ง€ ์•Š์Œ.


๐Ÿ”– ์ฐธ๊ณ ์ž๋ฃŒ

RESTful API ๊ตฌํ˜„ํ•˜๊ธฐ

REST API๋ž€?