REST API
REST๋ย ๋ ์์คํ
๊ฐ์ ํต์ ์ ์ํ ์ํคํ
์ฒ ์คํ์ผ๋ก, Representational State Transfer์ ์ฝ์์ด๋ค. REST API๋ REST ์คํ์ผ์ ์ฌ์ฉํ์ฌ ๊ตฌํ๋ API๋ฅผ ๋ถ๋ฅด๋ ๋ช
์นญ์ด๋ค.
REST๋ 2000๋
๋ก์ด ํ๋ฉ(Roy Fielding)์ ๋
ผ๋ฌธ์์ ์ ์๋์๋๋ฐ, ํต์ฌ์ ๋จ์ํ๋ค.
๋ฆฌ์์ค๋ฅผ URI๋ก ํํํ๊ณ , ์ํ์ ์ ์ก์ HTTP๋ก ์ํํ๋ค.
๋ค์ ๋งํด, REST๋ โ๋ฌด์์ ์์ฒญํ ์งโ์ โ์ด๋ป๊ฒ ์์ฒญํ ์งโ๋ฅผ ๊ตฌ๋ถํ์ฌ ํํํ๋ ๊ท์น์ผ๋ก, ์น์์ ์์์ URI๋ก ์ ์ํ๊ณ , GET, POST, PUT, DELETE ๋ฑ์ HTTP ๋ฉ์๋๋ฅผ ์ฌ์ฉํด ์์์ ์ํ๋ฅผ ์ฃผ๊ณ ๋ฐ๋ ์์ผ๋กย ํด๋ผ์ด์ธํธ์ ์๋ฒ๊ฐ ์ ํด์ง ๊ท์น์ ๋ฐ๋ผ ์๋ก ์์ฒญ๊ณผ ์๋ต์ ์ฃผ๊ณ ๋ฐ๋๋ก ํ๋ค.
REST API์ ํต์ฌ์์
๋ฆฌ์์ค (Resource)
๋ฆฌ์์ค๋ ์ฌ์ฉ์, ๊ฒ์๊ธ, ์ฃผ๋ฌธ ๋ฑ ์๋ฒ๊ฐ ๋ค๋ฃจ๋ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ์๋ฏธํ๋ฉฐ, ๊ณ ์ ํ ์๋ณ์์ธ URI๋ฅผ ๊ฐ์ง๋ค.
GET /users GET /posts/42
HTTP ๋ฉ์๋
REST๋ HTTP ๋ฉ์๋๋ฅผ ์ด์ฉํด ๋ฆฌ์์ค์ ๋ํด ์ํํ ๋์์ ๋ํ๋ธ๋ค.
์ผ๋ฐ์ ์ธ CRUD(Create, Read, Update, Delete) ์์
์ด ์๋์ ๊ฐ์ด ๊ฐ ๋ฉ์๋๋ก ํํ๋๋ค.
- GET: ์กฐํ(Read) โ ๋ฆฌ์์ค๋ฅผ ๊ฐ์ ธ์จ๋ค
- POST: ์์ฑ(Create) โ ์๋ก์ด ๋ฆฌ์์ค๋ฅผ ๋ง๋ ๋ค
- PUT: ์ ์ฒด ์์ (Update) โ ๋ฆฌ์์ค ์ ์ฒด๋ฅผ ๋ฎ์ด์ด๋ค
- PATCH: ์ผ๋ถ ์์ (Update) โ ๋ฆฌ์์ค์ ์ผ๋ถ๋ฅผ ๋ณ๊ฒฝํ๋ค
- DELETE ์ญ์ (Delete) โ ๋ฆฌ์์ค๋ฅผ ์ ๊ฑฐํ๋ค
// ์๋ก์ด ์ฌ์ฉ์ ๋ฆฌ์์ค๋ฅผ ๋ง๋ ๋ค. POST /users // ์์ฑ๋์ด ์๋ ์ฌ์ฉ์ ๋ฆฌ์์ค๋ฅผ ์กฐํํ๋ค GET /users/1
ํํ (Representation)
์์์ ์ํ๋ฅผ ๋ํ๋ด๋ ์ ๋ณด์ ํ์์ผ๋ก REST API๋ ์ผ๋ฐ์ ์ผ๋ก JSON์ ์ฌ์ฉํ๋ค.
- ์์ฒญ
POST /users Content-Type: application/json { "name": "Lucas", "email": "clee0627@gmail.com" }
- ์๋ต
HTTP/1.1 201 Created Content-Type: application/json { "id": 1, "name": "Lucas", "email": "clee0627@gmail.com" }
ย
REST์ ํน์ง๊ณผ ์ฅ์
- Server-Client ๊ตฌ์กฐ: ์๋ฒ์ ํด๋ผ์ด์ธํธ๋ก ์ด๋ฃจ์ด์ง ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๋ฉฐ ๋์ ์๋ก ๋ ๋ฆฝ์ ์ผ๋ก ๊ฐ๋ฐ๋ ์ ์๋ค. ์ด๋ก ์ธํด ์์คํ ์ ํ์ฅ ๋ฐ ๋ณ๊ฒฝ์ด ์ฉ์ดํ๋ค.
- ์ธํฐํ์ด์ค ์ผ๊ด์ฑ (Uniform Interface): ์์ฒญ์ ์๋ฏธ๋ HTTP ๋ฉ์๋/์ํ์ฝ๋/ํ์ดํผ๋ฏธ๋์ด๋ก ์ผ๊ด๋๊ฒ ์ ๋ฌ๋๋ค. API์ ๋ช ํํ ์์ฒญ๊ณผ ์๋ต ๊ตฌ์กฐ ๋๋ถ์ ๊ฐ๋ฐ์๋ค์ด API๋ฅผ ์ดํดํ๊ณ ์ฌ์ฉํ๋ฉฐ ์ ์ง๋ณด์ํ๊ธฐ๊ฐ ์ฉ์ดํ๋ค.
- ๊ณ์ธตํ (Layered System): ํด๋ผ์ด์ธํธ์ ์๋ฒ ๊ฐ์ ํต์ ์ ์ฌ๋ฌ ๊ณ์ธต์ผ๋ก ๋ถ๋ฆฌํ์ฌ ํด๋ผ์ด์ธํธ๊ฐ ์ค์ ์๋ฒ๋ฅผ ์ง์ ์์ง ๋ชปํ๊ฒ ํ๋ค. ์ด ๊ณผ์ ์์ ํด๋ผ์ด์ธํธ๋ ์ค๊ฐ ๊ณ์ธต(์บ์, ๊ฒ์ดํธ์จ์ด)์ด ์์์ ์ ๊ฒฝ ์ธ ํ์๊ฐ ์์ผ๋ฉฐ ์ด๋ฅผ ํตํด ํ์ฅ์ฑ, ์ ์ฐ์ฑ, ๋ณด์์ฑ์ ๋์ธ๋ค.
- ๋ฌด์ํ (Statetless): ์๋ฒ๋ ํด๋ผ์ด์ธํธ ์ํ๋ฅผ ์ ์งํ์ง ์์ผ๋ฉฐ ๊ฐ ์์ฒญ์ ํ์ํ ๋ชจ๋ ์ ๋ณด๋ฅผ ๋ด์์ผ ํ๋ค. ์ํ๋ฅผ ์๋ฒ๊ฐ ๊ธฐ์ตํ ํ์๊ฐ ์์ผ๋ฏ๋ก ์๋ฒ ํ์ฅ์ฑ๊ณผ ๊ฐ์ฉ์ฑ์ด ์ข๋ค.
๋จ์ ๊ณผ ํ๊ณ
REST๋ ๊ท์น์ด ๋จ์ํ๊ณ ๋ช
ํํ๊ธฐ ๋๋ฌธ์ ๋ง์ด ์ฌ์ฉ๋์ง๋ง ์ํคํ
์ฒ ์คํ์ผ์ผ ๋ฟ ์๊ฒฉํ ํ์ค ๊ท์ฝ์ด ์กด์ฌํ์ง๋ ์๋๋ค. ๊ทธ๋์ ๊ฐ๋ฐ์์ ์ญ๋์ด๋ ๊ด์ ์ ๋ฐ๋ผ ๋ค๋ฅด๊ฒ ์ค๊ณ๋ ์ ์๊ณ REST์ ๊ธฐ๋ณธ ์์น์ ์งํค์ง ์๊ณ ๋ REST API ์ฒ๋ผ ์ฌ์ฉ๋๋ ์ํฐํจํด์ด ์ ์ฉ๋ ๊ฐ๋ฅ์ฑ์ด ๋๋ค.
๋ํ ์์ฒญ๊ณผ ์๋ต์ผ๋ก ์ด๋ฃจ์ด์ง ๊ตฌ์กฐ์ ๊ด๊ณ ๋ฐ์ดํฐ๊ฐ ๋ณต์กํ ๊ฒฝ์ฐ ๋ฐ๋ณตํด์ ์์ฒญ์ ํด์ผํ๊ฑฐ๋ ์ค์๊ฐ์ผ๋ก ๋ณ๊ฒฝ๋๋ ๋ฐ์ดํฐ๋ฅผ ์ง์์ ์ผ๋ก ์ฒ๋ฆฌํด์ผํ๋ ๊ฒฝ์ฐ์๋ ๋ง์ง ์๋๋ค. ๊ทธ๋์ ์ต๊ทผ์๋ GraphQL, gRPC, WebSocket API ๊ฐ์ ๋ค๋ฅธ ์ ๊ทผ๋ฒ์ด ํจ๊ป ์ฌ์ฉ๋๋ค.
RESTful
์์ ๋งํ๋ฏ REST๋ ์๊ฒฉํ ํ์ค ๊ท์ฝ์ด ์์ง ์๊ธฐ ๋๋ฌธ์ ์ํฐํจํด์ด ์ ์ฉ๋๊ธฐ ์ฝ๋ค. ๊ทธ๋์ REST ์ํคํ
์ฒ ์์น์ ์ต๋ํ ์ ์ค์ฒํ๋ ๊ฒ์ โRESTfulโ์ด๋ผ๊ณ ํํํ๋ค.
๋จ์ํ HTTP ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๊ณ URI๋ก ๋ฆฌ์์ค ๊ด๊ณ๋ฅผ ๋ํ๋๋ค๊ณ RESTful ํ ๊ฒ์ด ์๋๋ฐ, REST ์ํคํ
์ฒ ์์น์ ์ ๋ฐ๋ฅด๊ธฐ ์ํด์๋ ๋ฆฌ์์ค ์ค์ฌ ์ค๊ณ, ๋ฌด์ํ์ฑ, ์ผ๊ด๋ ์ธํฐํ์ด์ค, ๊ทธ๋ฆฌ๊ณ ํ์ดํผ๋ฏธ๋์ด(HATEOAS) ๊ฐ์ ๊ฐ๋
์ด ์ ์ง์ผ์ ธ์ผ ํ๋ค.
HATEOAS (Hypermedia As The Engine Of Application State)
HATEOAS๋ REST ์์น ์ค ์ผ๊ด๋ ์ธํฐํ์ด์ค๋ฅผ ์งํฌ ์ ์๋๋ก ํ๊ธฐ ์ํด ๋์จ ๊ฐ๋
์ผ๋ก ๊ธฐ๋ณธ์ ์ธ ์์ด๋์ด๋ ํ์ดํผ๋ฏธ๋์ด๋ฅผ ์ดํ๋ฆฌ์ผ์ด์
์ ์ํ๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ํ ์๋จ์ผ๋ก ์ฌ์ฉํ๋ ๊ฒ์ด๋ค.
๋ ์ฝ๊ฒ ํํํ๋ฉด, ์๋ฒ๊ฐ ์๋ต์ ๋ค์ ๊ฐ๋ฅํ ํ๋(์ํ ์ ํ)์ ๋ํ๋ด๋ ํ์ดํผ๋งํฌ(๋งํฌ ๋ฉํ๋ฐ์ดํฐ)๋ฅผ ํฌํจ์์ผ ํด๋ผ์ด์ธํธ๊ฐ ์ค์ค๋ก ์ดํ๋ฆฌ์ผ์ด์
์ ํ๋ฆ์ ๋ฐ๊ฒฌํ๋๋ก ํ๋ ๋ฐฉ๋ฒ์ผ๋ก ํด๋ผ์ด์ธํธ๋ ์๋ฒ ์๋ต์์ ์ด๋ค URL์ ํธ์ถํด์ผ ๋ค์ ํ๋์ ํ ์ ์๋์ง์ ๋ํด ํ์
ํ ์ ์๋ค.
HATEOAS ๊ฐ๋ ์ ์๋
- ํด๋ผ์ด์ธํธ-์๋ฒ ๊ณ์ฝ์ ๋์จํ๊ฒ ๋ง๋ ๋ค โ ์๋ฒ๊ฐ ๊ฐ๋ฅํ ํ๋์ ๋งํฌ๋ก ์ ๊ณตํ๋ฉด, ํด๋ผ์ด์ธํธ๋ URL ๊ท์น์ ํ๋์ฝ๋ฉํ์ง ์์๋ ๋๋ค.
- ์๋ฒ ์์ , ์ ์ง๊ด๋ฆฌ์ ์ ๋ฆฌ โ ์๋ฒ๊ฐ ๋งํฌ ๊ตฌ์กฐ๋ฅผ ๋ฐ๊ฟ๋ ํด๋ผ์ด์ธํธ๋ ์๋ต์ ํฌํจ๋ ๋งํฌ๋ง ๋ฐ๋ฅด๋ฉด ๋๋ค.
- ์ฌ์ฉ์ ํ๋ฆ(์ํฌํ๋ก์ฐ)์ ๋ช ์ โ ํ์ฌ ์ํ์์ ์ด๋ค ํ๋์ด ํ์ฉ๋๋์ง, ์ด๋ค ๊ด๊ณ(์: cancel, next, approve)๊ฐ ์๋์ง ํํ ๊ฐ๋ฅ.
์๋ฒ ์๋ต ์์
{ "data": { "type": "articles", "id": "42", "attributes": { "title": "REST์ HATEOAS", "body": "..." } }, "links": { "self": "/articles/42", "comments": "/articles/42/comments", "author": "/users/7" }, "actions": { "edit": { "method": "PATCH", "href": "/articles/42", "title": "Edit this article" }, "delete": { "method": "DELETE", "href": "/articles/42" } } }
์ฆ, HATEOAS๋ ๊ฐ๋ฐ์๊ฐ ๋ณต์กํ API ๋ฌธ์๋ฅผ ์์ฑํ๊ณ ๊ทธ ๋ด์ฉ๊ณผ ๊ท์น๋ค์ ํด๋ผ์ด์ธํธ ์ชฝ์์ ๋ชจ๋ ํ์
ํ๊ณ ์์ง ์์๋ ๊ฐ๋ฐ์ ๋ฌธ์ ๊ฐ ์๋๋ก ํ์ฌ REST ์์น์ ๋ฐ๋ฅผ ์ ์๊ฒ ํด์ฃผ๋ ๋ฐฉ๋ฒ์ด๋ค.
ย