๐Ÿ“š [Spring] Restful API, Entity & DTO

์ด๊ฐ€์€ยท2024๋…„ 5์›” 23์ผ
0

Spring

๋ชฉ๋ก ๋ณด๊ธฐ
11/13
post-thumbnail

๐Ÿ“• Postman

Postman ์„ค์น˜

๐Ÿ“– Postman ์‹คํ–‰ ํ™”๋ฉด

โœ” ๐ŸŸฅ์— ์–ด๋–ค ํ˜•์‹์œผ๋กœ URL์„ ์š”์ฒญํ•  ๊ฑด์ง€ ์„ ํƒ

โœ” ๐ŸŸฅ์— API URL์„ ์ž‘์„ฑํ•˜๊ณ  ๐ŸŸฆ์— Body๋กœ ๋ณด๋‚ผ ๊ฐ’์„ ์ž‘์„ฑํ•œ ํ›„ ๐ŸŸง์„ ๋ˆ„๋ฅธ๋‹ค

๐Ÿ“™ HTTP Method

โ—ฝ ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„ ์‚ฌ์ด์— ์ด๋ฃจ์–ด์ง€๋Š” ์š”์ฒญ(Request)๊ณผ ์‘๋‹ต(Response) ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๋Š” ๋ฐฉ์‹
โ—ฝ ์„œ๋ฒ„์— ์ฃผ์–ด์ง„ ๋ฆฌ์†Œ์Šค์— ์ˆ˜ํ–‰ํ•˜๊ธธ ์›ํ•˜๋Š” ํ–‰๋™, ์„œ๋ฒ„๊ฐ€ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•  ๋™์ž‘์„ ์ง€์ •ํ•˜๋Š” ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ๋ฐฉ๋ฒ•

๐ŸŽˆ ์ฃผ์š” ๋ฉ”์†Œ๋“œ
GET :ย ๋ฆฌ์†Œ์Šค ์กฐํšŒ
POST : ย ์š”์ฒญ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ, ์ฃผ๋กœ ๋“ฑ๋ก์— ์‚ฌ์šฉ
PUT :ย ๋ฆฌ์†Œ์Šค๋ฅผ ๋Œ€์ฒด(๋ฎ์–ด์“ฐ๊ธฐ), ํ•ด๋‹น ๋ฆฌ์†Œ์Šค๊ฐ€ ์—†์œผ๋ฉด ์ƒ์„ฑ
PATCH :ย ๋ฆฌ์†Œ์Šค ๋ถ€๋ถ„ ๋ณ€๊ฒฝ (PUT์ด ์ „์ฒด ๋ณ€๊ฒฝ, PATCH๋Š” ์ผ๋ถ€ ๋ณ€๊ฒฝ)
DELETE :ย ๋ฆฌ์†Œ์Šค ์‚ญ์ œ

๐ŸŽˆ ๊ธฐํƒ€ ๋ฉ”์†Œ๋“œ
HEAD :ย GET๊ณผ ๋™์ผํ•˜์ง€๋งŒ ๋ฉ”์‹œ์ง€ ๋ถ€๋ถ„(body ๋ถ€๋ถ„)์„ ์ œ์™ธํ•˜๊ณ , ์ƒํƒœ ์ค„๊ณผ ํ—ค๋”๋งŒ ๋ฐ˜ํ™˜
OPTIONS :ย ๋Œ€์ƒ ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ํ†ต์‹  ๊ฐ€๋Šฅ ์˜ต์…˜(๋ฉ”์†Œ๋“œ)์„ ์„ค๋ช…(์ฃผ๋กœ CORS์—์„œ ์‚ฌ์šฉ)
CONNECT :ย ๋Œ€์ƒ ์ž์›์œผ๋กœ ์‹๋ณ„๋˜๋Š” ์„œ๋ฒ„์— ๋Œ€ํ•œ ํ„ฐ๋„์„ ์„ค์ •
TRACE :ย ๋Œ€์ƒ ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ๊ฒฝ๋กœ๋ฅผ ๋”ฐ๋ผ ๋ฉ”์‹œ์ง€ ๋ฃจํ”„๋ฐฑ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰

๐Ÿ“– GET ๋ฉ”์†Œ๋“œ

โ—พ ๋ฆฌ์†Œ์Šค ์กฐํšŒ ๋ฉ”์†Œ๋“œ (Read)
โ—พ ๋งŒ์ผ ํ‹€์„œ๋ฒ„์— ์ „๋‹ฌํ•˜๊ณ  ์‹ถ์€ ๋ฐ์ดํ„ฐ๋Š” ์ฟผ๋ฆฌ์ŠคํŠธ๋ง๋ฅผ ํ†ตํ•ด์„œ ์ „๋‹ฌ
GET /members/100?username=inpa&height=200
โ—พ ์ฟผ๋ฆฌ์ŠคํŠธ๋ง ์™ธ์— ๋ฉ”์‹œ์ง€ ๋ฐ”๋””๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์„œ๋ฒ„์—์„œ ๋”ฐ๋กœ ๊ตฌ์„ฑํ•ด์•ผ ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๊ณณ์ด ๋งŽ์•„์„œ ๊ถŒ์žฅํ•˜์ง€ ์•Š์Œ
โ—พ ์กฐํšŒํ•  ๋•Œ POST๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, GET ๋ฉ”์†Œ๋“œ๋Š” ์บ์‹ฑ์ด ๊ฐ€๋Šฅํ•˜๊ธฐ์—ย GET์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์œ ๋ฆฌํ•˜๋‹ค.

๐Ÿ“– POST ๋ฉ”์†Œ๋“œ

โ—พ ์ „๋‹ฌํ•œ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ/์ƒ์„ฑ ์š”์ฒญ ๋ฉ”์†Œ๋“œ (Create)
โ—พ ๋ฉ”์‹œ์ง€ ๋ฐ”๋””(body)๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„๋กœ ์š”์ฒญ ๋ฐ์ดํ„ฐ ์ „๋‹ฌํ•˜๋ฉด ์„œ๋ฒ„๋Š” ์š”์ฒญ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜์—ฌ ์—…๋ฐ์ดํŠธ
โ—พ ์ „๋‹ฌ๋œ ๋ฐ์ดํ„ฐ๋กœ ์ฃผ๋กœ ์‹ ๊ทœ ๋ฆฌ์†Œ์Šค ๋“ฑ๋ก, ํ”„๋กœ์„ธ์Šค ์ฒ˜๋ฆฌ์— ์‚ฌ์šฉ
โ—พ ๋งŒ์ผ ๋ฐ์ดํ„ฐ๋ฅผ GET ํ•˜๋Š”๋ฐ ์žˆ์–ด, JSON์œผ๋กœ ์กฐํšŒ ๋ฐ์ดํ„ฐ๋ฅผ ๋„˜๊ฒจ์•ผ ํ•˜๋Š” ์• ๋งคํ•œ ๊ฒฝ์šฐ POST๋ฅผ ์‚ฌ์šฉ

๐Ÿ“– PUT ๋ฉ”์†Œ๋“œ

โ—พ ๋ฆฌ์†Œ์Šค๋ฅผ ๋Œ€์ฒด(์ˆ˜์ •)ํ•˜๋Š” ๋ฉ”์†Œ๋“œ (Update)
โ—พ ๋งŒ์ผ ์š”์ฒญ ๋ฉ”์„ธ์ง€์— ๋ฆฌ์†Œ์Šค๊ฐ€ ์žˆ์œผ๋ฉด ๋ฎ์–ด์“ฐ๊ณ , ์—†์œผ๋ฉด ์ƒˆ๋กœ ์ƒ์„ฑํ•œ๋‹ค.

/members/100 ๋ฐ์ดํ„ฐ๊ฐ€ ์กด์žฌํ•˜๋ฉด ๊ธฐ์กด์— ๊ฒƒ์„ ์™„์ „ ๋Œ€์ฒด ํ•œ๋‹ค.
/members/100 ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์œผ๋ฉด ๋Œ€์ฒด ํ• ๊ฒŒ ์—†์œผ๋‹ˆ๊นŒ ์ƒˆ๋กœ ์ƒ์„ฑํ•œ๋‹ค.

โ—พ ๋ฐ์ดํ„ฐ๋ฅผ ๋Œ€์ฒดํ•ด์•ผ ํ•˜๋‹ˆ, ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ฆฌ์†Œ์Šค์˜ ๊ตฌ์ฒด์ ์ธ ์ „์ฒด ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•ด ๋ณด๋‚ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

POST /members : ๋ฉค๋ฒ„ ์ƒˆ๋กœ ์ถ”๊ฐ€
PUT /members/100 : 100๋ฒˆ์งธ ๋ฉค๋ฒ„ ์ˆ˜์ •

โ“ ์ผ๋ถ€ ๋ฆฌ์†Œ์Šค๋งŒ ๋ณ€๊ฒฝํ•˜๊ธธ ์›ํ•œ๋‹ค๋ฉด? PATCH ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์ž!

๐Ÿ“– PATCH ๋ฉ”์†Œ๋“œ

โ—พ ๋ฆฌ์†Œ์Šค ์ผ๋ถ€ ๋ถ€๋ถ„์„ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฉ”์†Œ๋“œ (Update)
โ—พ ๋งŒ์ผ PATCH๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ์„œ๋ฒ„์—์„œ๋Š” ๋Œ€์‹ ์— POST๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ“– DELETE ๋ฉ”์†Œ๋“œ

โ—พ ๋ฆฌ์†Œ์Šค ์ œ๊ฑฐํ•˜๋Š” ๋ฉ”์†Œ๋“œ (Delete)
โ—พ ์ƒํƒœ์ฝ”๋“œ๋Š” ๋Œ€๋ถ€๋ถ„ 200์„ ์‚ฌ์šฉํ•˜๊ณ  ์ƒํ™ฉ์— ๋”ฐ๋ผ 204๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

๐Ÿ“– HEAD ๋ฉ”์†Œ๋“œ

โ—พ GET๊ณผ ๋™์ผํ•˜์ง€๋งŒย ์„œ๋ฒ„์—์„œ Body๋ฅผ Return ํ•˜์ง€ ์•Š์Œ
โ—พ ์‘๋‹ต์˜ ์ƒํƒœ ์ฝ”๋“œ๋งŒ ํ™•์ธํ• ๋•Œ์™€ ๊ฐ™์ด Resource๋ฅผ ๋ฐ›์ง€ ์•Š๊ณ  ์˜ค์ง ์ฐพ๊ธฐ๋งŒ ์›ํ• ๋•Œ ์‚ฌ์šฉ (์ผ์ข…์˜ ๊ฒ€์‚ฌ ์šฉ๋„)
โ—พ ์„œ๋ฒ„์˜ ์‘๋‹ต ํ—ค๋”๋ฅผ ๋ด„์œผ๋กœ์จ Resource๊ฐ€ ์ˆ˜์ •๋˜์—ˆ๋Š”์ง€ ํ™•์ธ ๊ฐ€๋Šฅ

๐Ÿ“– TRACE ๋ฉ”์†Œ๋“œ

โ—พ ์ด ๋ฉ”์„œ๋“œ๋„ ์ผ์ข…์˜ ๊ฒ€์‚ฌ์šฉ
โ—พ ์„œ๋ฒ„์— ๋„๋‹ฌ ํ–ˆ์„ ๋•Œ์˜ ์ตœ์ข… ํŒจํ‚ท์˜ ์š”์ฒญ ํŒจํ‚ท ๋‚ด์šฉ์„ ์‘๋‹ต ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.
โ—พ ์š”์ฒญ์˜ ์ตœ์ข… ์ˆ˜์‹ ์ž๋Š” ๋ฐ˜๋“œ์‹œย ์†ก์‹ ์ž์—๊ฒŒ 200(OK) ์‘๋‹ต์˜ ๋‚ด์šฉ(Body)๋กœ ์ˆ˜์‹ ํ•œ ๋ฉ”์„ธ์ง€๋ฅผ ๋ฐ˜์†กํ•ด์•ผ ํ•œ๋‹ค.
โ—พ ์ตœ์ดˆ Client์˜ ์š”์ฒญ์—๋Š” Body๊ฐ€ ํฌํ•จ๋ ์ˆ˜ ์—†๋‹ค.

๐Ÿ“– OPTION ๋ฉ”์†Œ๋“œ

โ—พ ์˜ˆ๋น„ ์š”์ฒญ(Preflight)์— ์‚ฌ์šฉ๋˜๋Š” HTTP ๋ฉ”์†Œ๋“œ
โ—พ ์˜ˆ๋น„ ์š”์ฒญ์ด๋ž€ ๋ณธ ์š”์ฒญ์„ ํ•˜๊ธฐ ์ „์— ์•ˆ์ „ํ•œ์ง€ ๋ฏธ๋ฆฌ ๊ฒ€์‚ฌํ•˜๋Š” ๊ฒƒ์ด๋ผ๊ณ  ๋ณด๋ฉด ๋œ๋‹ค
โ—พ ์„œ๋ฒ„์˜ ์ง€์› ๊ฐ€๋Šฅํ•œ HTTP ๋ฉ”์„œ๋“œ์™€ ์ถœ์ฒ˜๋ฅผ ์‘๋‹ต ๋ฐ›์•„ CORS ์ •์ฑ…์„ ๊ฒ€์‚ฌํ•˜๊ธฐ ์œ„ํ•œ ์š”์ฒญ์ด๋‹ค.

๐Ÿ“– Content-Type ํ—ค๋” ์ข…๋ฅ˜

Content-Type: application/x-www-form-urlencoded
โ—พ Form์˜ ๋‚ด์šฉ์„ HTTP ๋ฉ”์‹œ์ง€ ๋ฐ”๋””๋ฅผ ํ†ตํ•ด์„œ ์ „์†ก(key=value, ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ ํ˜•์‹)
โ—พ ์ „์†ก ๋ฐ์ดํ„ฐ๋ฅผ url encoding ์ฒ˜๋ฆฌ
โ—พ ์˜ˆ) abc๊น€ โ†’ abc%EA%B9%80

Content-Type: multipart/form-data
โ—พ ํŒŒ์ผ ์—…๋กœ๋“œ ๊ฐ™์€ ๋ฐ”์ด๋„ˆ๋ฆฌ ๋ฐ์ดํ„ฐ ์ „์†ก ์‹œ ์‚ฌ์šฉ
โ—พ ๋‹ค๋ฅธ ์ข…๋ฅ˜์˜ ์—ฌ๋Ÿฌ ํŒŒ์ผ๊ณผ Form์˜ ๋‚ด์šฉ ํ•จ๊ป˜ ์ „์†ก ๊ฐ€๋Šฅ

Content-Type: application/json
โ—พ TEXT, XML, JSON ๋ฐ์ดํ„ฐ ์ „์†ก ์‹œ ์‚ฌ์šฉ

๐Ÿ“’ RESTful API

โ—ฝ REST API์—์„œ REST๋Š” Representational State Transfer์˜ ์•ฝ์ž๋กœ ์†Œํ”„ํŠธ์›จ์–ด ํ”„๋กœ๊ทธ๋žจ ์•„ํ‚คํ…์ฒ˜์˜ ํ•œ ํ˜•์‹์ด๋‹ค
โ—ฝ ์ž์›์„ ์ด๋ฆ„ (์ž์›์˜ ํ‘œํ˜„) ์œผ๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ ํ•ด๋‹น ์ž์›์˜ ์ƒํƒœ (์ •๋ณด)๋ฅผ ์ฃผ๊ณ  ๋ฐ›๋Š” ๋ชจ๋“  ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค
โ—ฝ ์›”๋“œ ์™€์ด๋“œ ์›น (WWW) ๊ณผ ๊ฐ™์€ ๋ถ„์‚ฐ ํ•˜์ดํผ๋ฏธ๋””์–ด ์‹œ์Šคํ…œ์„ ์œ„ํ•œ ์†Œํ”„ํŠธ์›จ์–ด ๊ฐœ๋ฐœ ์•„ํ‚คํ…์ฒ˜์˜ ํ•œ ํ˜•์‹
โ—ฝ REST๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์›น์˜ ๊ธฐ์กด ๊ธฐ์ˆ ๊ณผ HTTP ํ”„๋กœํ† ์ฝœ์„ ๊ทธ๋Œ€๋กœ ํ™œ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์›น์˜ ์žฅ์ ์„ ์ตœ๋Œ€ํ•œ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์•„ํ‚คํ…์ฒ˜ ์Šคํƒ€์ผ์ด๋‹ค

๐Ÿ“– REST ๊ตฌ์„ฑ

โ—พ ์ž์›(RESOURCE) - URI
โ—พ ํ–‰์œ„(Verb) - HTTP METHOD
โ—พ ํ‘œํ˜„(Representations)

๐Ÿ“– REST์˜ ํŠน์ง•

1) Uniform (์œ ๋‹ˆํผ ์ธํ„ฐํŽ˜์ด์Šค)
โ—พ Uniform Interface๋Š” Http ํ‘œ์ค€์—๋งŒ ๋”ฐ๋ฅธ๋‹ค๋ฉด ๋ชจ๋“  ํ”Œ๋žซํผ์—์„œ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๋ฉฐ, URI๋กœ ์ง€์ •ํ•œ ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ์กฐ์ž‘์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋Š” ์•„ํ‚คํ…์ณ ์Šคํƒ€์ผ์„ ๋งํ•œ๋‹ค
โ—พ URI๋กœ ์ง€์ •ํ•œ Resource์— ๋Œ€ํ•œ ์กฐ์ž‘์„ ํ†ต์ผ๋˜๊ณ  ํ•œ์ •์ ์ธ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์ˆ˜ํ–‰ํ•œ๋‹ค
โ—พ ์ฆ‰, ํŠน์ • ์–ธ์–ด๋‚˜ ๊ธฐ์ˆ ์— ์ข…์†๋˜์ง€ ์•Š๋Š”๋‹ค

2) Stateless (๋ฌด์ƒํƒœ์„ฑ)
โ—พ REST๋Š” HTTP์˜ ํŠน์„ฑ์„ ์ด์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฌด์ƒํƒœ์„ฑ ์„ฑ๊ฒฉ์„ ๊ฐ–๋Š”๋‹ค -> ์ž‘์—…์„ ์œ„ํ•œ ์ƒํƒœ์ •๋ณด๋ฅผ ๋”ฐ๋กœ ์ €์žฅํ•˜๊ณ  ๊ด€๋ฆฌํ•˜์ง€ ์•Š๋Š”๋‹ค
โ—พ ์„ธ์…˜ ์ •๋ณด๋‚˜ ์ฟ ํ‚ค์ •๋ณด๋ฅผ ๋ณ„๋„๋กœ ์ €์žฅํ•˜๊ณ  ๊ด€๋ฆฌํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— API ์„œ๋ฒ„๋Š” ๋“ค์–ด์˜ค๋Š” ์š”์ฒญ๋งŒ์„ ๋‹จ์ˆœํžˆ ์ฒ˜๋ฆฌํ•˜๋ฉด ๋œ๋‹ค. ๋•Œ๋ฌธ์— ์„œ๋น„์Šค์˜ ์ž์œ ๋„๊ฐ€ ๋†’์•„์ง€๊ณ  ์„œ๋ฒ„์—์„œ ๋ถˆํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ๊ด€๋ฆฌํ•˜์ง€ ์•Š์Œ์œผ๋กœ์จ ๊ตฌํ˜„์ด ๋‹จ์ˆœํ•ด์ง„๋‹ค

3) Cacheable (์บ์‹œ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ)
โ—พ HTTP๋ผ๋Š” ๊ธฐ์กด ์›นํ‘œ์ค€์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์›น์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ์กด ์ธํ”„๋ผ๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค
โ—พ ๋”ฐ๋ผ์„œ HTTP๊ฐ€ ๊ฐ€์ง„ ์บ์‹ฑ ๊ธฐ๋Šฅ์ด ์ ์šฉ ๊ฐ€๋Šฅํ•œ๋‹ค
โ—พ ์บ์‹œ ์‚ฌ์šฉ์„ ํ†ตํ•ด ์‘๋‹ต์‹œ๊ฐ„์ด ๋นจ๋ผ์ง€๊ณ  REST Server ํŠธ๋žœ์žญ์…˜์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ „์ฒด ์‘๋‹ต์‹œ๊ฐ„, ์„ฑ๋Šฅ, ์„œ๋ฒ„์˜ ์ž์› ์ด์šฉ๋ฅ ์„ ํ–ฅ์ƒ ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค

4) Self-descriptiveness (์ž์ฒด ํ‘œํ˜„ ๊ตฌ์กฐ)
โ—พ REST API ๋ฉ”์‹œ์ง€๋งŒ ๋ณด๊ณ ๋„ ๊ทธ ์š”์ฒญ์ด ์–ด๋–ค ํ–‰์œ„๋ฅผ ํ•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ๋‹ค

5) Client - Server ๊ตฌ์กฐ
โ—พ ํด๋ผ์ด์–ธํŠธ๋Š” ์œ ์ €์™€ ๊ด€๋ จ๋œ ์ฒ˜๋ฆฌ๋ฅผ, ์„œ๋ฒ„๋Š” REST API๋ฅผ ์ œ๊ณตํ•จ์œผ๋กœ์จ ๊ฐ๊ฐ์˜ ์—ญํ™œ์ด ํ™•์‹คํ•˜๊ฒŒ ๊ตฌ๋ถ„๋˜๊ณ  ์ผ๊ด„์ ์ธ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๋ถ„๋ฆฌ๋˜์–ด ์ž‘๋™ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค
โ—พ REST Server : API๋ฅผ ์ œ๊ณตํ•˜๊ณ  ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง ์ฒ˜๋ฆฌ ๋ฐ ์ €์žฅ์„ ์ฑ…์ž„์ง„๋‹ค
โ—พ Client : ์‚ฌ์šฉ์ž ์ธ์ฆ์ด๋‚˜ context (์„ธ์…˜, ๋กœ๊ทธ์ธ ์ •๋ณด) ๋“ฑ์„ ์ง์ ‘ ๊ด€๋ฆฌํ•˜๊ณ  ์ฑ…์ž„์ง„๋‹ค
โ—พ ์„œ๋กœ ๊ฐ„ ์˜์กด์„ฑ์ด ์ค„์–ด๋“ ๋‹ค

6) Layered System (๊ณ„์ธตํ™”)
โ—พ ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„๊ฐ€ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ค‘๊ฐ„์— ํ”„๋ก์‹œ ์„œ๋ฒ„, ์•”ํ˜ธํ™” ๊ณ„์ธต ๋“ฑ ์ค‘๊ฐ„๋งค์ฒด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด ์ž์œ ๋„๊ฐ€ ๋†’๋‹ค

๐Ÿ“– REST API ๋””์ž์ธ ๊ฐ€์ด๋“œ

๐ŸŽˆ REST API ์ค‘์‹ฌ ๊ทœ์น™

โœ” URI๋Š” ์ •๋ณด์˜ ์ž์›์„ ํ‘œํ˜„ํ•ด์•ผ ํ•œ๋‹ค.

GET /members/delete/1

-> REST๋ฅผ ์ œ๋Œ€๋กœ ์ ์šฉํ•˜์ง€ ์•Š์€ URI
URI๋Š” ์ž์›์„ ํ‘œํ˜„ํ•˜๋Š”๋ฐ ์ค‘์ ์„ ๋‘์–ด์•ผ ํ•œ๋‹ค. delete์™€ ๊ฐ™์€ ํ–‰์œ„์— ๋Œ€ํ•œ ํ‘œํ˜„์ด ๋“ค์–ด๊ฐ€์„œ๋Š” ์•ˆ๋œ๋‹ค.

โœ” ์ž์›์— ๋Œ€ํ•œ ํ–‰์œ„๋Š” HTTP Method(GET, POST, PUT, DELETE ๋“ฑ)๋กœ ํ‘œํ˜„ํ•œ๋‹ค.

DELETE /members/1

-> ์ž˜๋ชป๋œ URI๋ฅผ HTTP Method๋ฅผ ํ†ตํ•ด ์ˆ˜์ •ํ•ด ๋ณด๋ฉด ์œ„์™€ ๊ฐ™์ด ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค

๐ŸŽˆ URI ์„ค๊ณ„ ์‹œ ์ฃผ์˜ํ•  ์ 

1) ์Šฌ๋ž˜์‹œ ๊ตฌ๋ถ„์ž(/)๋Š” ๊ณ„์ธต ๊ด€๊ณ„๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๋ฐ ์‚ฌ์šฉ

http://restapi.example.com/houses/apartments
http://restapi.example.com/animals/mammals/whales

2) URI ๋งˆ์ง€๋ง‰ ๋ฌธ์ž๋กœ ์Šฌ๋ž˜์‹œ(/)๋ฅผ ํฌํ•จํ•˜์ง€ ์•Š๋Š”๋‹ค

http://restapi.example.com/houses/apartments/ (โŒ)
http://restapi.example.com/houses/apartments (โญ•)

3) ํ•˜์ดํ”ˆ(-)์€ URI ๊ฐ€๋…์„ฑ์„ ๋†’์ด๋Š”๋ฐ ์‚ฌ์šฉ

4) ๋ฐ‘์ค„(_)์€ URI์— ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค
-> ๋ฐ‘์ค„ ๋Œ€์‹  ํ•˜์ดํ”ˆ(-)์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค

5) URI ๊ฒฝ๋กœ์—๋Š” ์†Œ๋ฌธ์ž๊ฐ€ ์ ํ•ฉํ•˜๋‹ค
-> ๋Œ€์†Œ๋ฌธ์ž์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ๋ฆฌ์†Œ์Šค๋กœ ์ธ์‹ํ•˜๊ฒŒ ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค

6) ํŒŒ์ผ ํ™•์žฅ์ž๋Š” URI์— ํฌํ•จ์‹œํ‚ค์ง€ ์•Š๋Š”๋‹ค

http://restapi.example.com/members/soccer/345/photo.jpg (โŒ)

-> REST API์—์„œ๋Š” ๋ฉ”์‹œ์ง€ ๋ฐ”๋”” ๋‚ด์šฉ์˜ ํฌ๋งท์„ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•œ ํŒŒ์ผ ํ™•์žฅ์ž๋ฅผ URI ์•ˆ์— ํฌํ•จ์‹œํ‚ค์ง€ ์•Š๋Š”๋‹ค
-> ๋Œ€์‹  Accept Header๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค

GET / members/soccer/345/photo HTTP/1.1
Host: restapi.example.com
Accept: image/jpg

7) ๋ฆฌ์†Œ์Šค ๊ฐ„์— ์—ฐ๊ด€ ๊ด€๊ณ„๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ

/๋ฆฌ์†Œ์Šค๋ช…/๋ฆฌ์†Œ์Šค ID/๊ด€๊ณ„๊ฐ€ ์žˆ๋Š” ๋‹ค๋ฅธ ๋ฆฌ์†Œ์Šค๋ช…
ex) GET : /users/{userid}/devices (์ผ๋ฐ˜์ ์œผ๋กœ ์†Œ์œ ์˜ ๊ด€๊ณ„๋ฅผ ํ‘œํ˜„ํ•  ๋•Œ)

๋งŒ์•ฝ์— ๊ด€๊ณ„๋ช…์ด ๋ณต์žกํ•˜๋‹ค๋ฉด ์ด๋ฅผ ์„œ๋ธŒ ๋ฆฌ์†Œ์Šค์— ๋ช…์‹œ์ ์œผ๋กœ ํ‘œํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค

//์‚ฌ์šฉ์ž๊ฐ€ โ€˜์ข‹์•„ํ•˜๋Š”โ€™ ๋””๋ฐ”์ด์Šค ๋ชฉ๋ก์„ ํ‘œํ˜„ํ•ด์•ผ ํ•  ๊ฒฝ์šฐ
GET : /users/{userid}/likes/devices (๊ด€๊ณ„๋ช…์ด ์• ๋งคํ•˜๊ฑฐ๋‚˜ ๊ตฌ์ฒด์  ํ‘œํ˜„์ด ํ•„์š”ํ•  ๋•Œ)

๐Ÿ“– RESTful API

โ—ฝ RESTful์ด๋ž€, HTTP์™€ URI ๊ธฐ๋ฐ˜์œผ๋กœ ์ž์›์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ์ œ๊ณตํ•˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ ์ธํ„ฐํŽ˜์ด์Šค์ด๋‹ค
โ—ฝ REST API๋ฅผ ์ œ๊ณตํ•˜๋Š” ์›น ์„œ๋น„์Šค๋ฅผ 'RESTful'ํ•˜๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค
โ—ฝ RESTful API๋ž€, REST์˜ ์„ค๊ณ„ ๊ทœ์น™์„ ์ž˜ ์ง€์ผœ์„œ ์„ค๊ณ„๋œ API์ด๋‹ค

๐Ÿ“— @RestController

โ—ฝ @RestController ์–ด๋…ธํ…Œ์ด์…˜์€ @Controller์™€ @ResponseBody๊ฐ€ ํ•ฉ์ณ์ง„ ํ˜•ํƒœ๋กœ, REST API๋ฅผ ๊ฐœ๋ฐœํ•  ๋•Œ ์ฃผ๋กœ ์‚ฌ์šฉ๋œ๋‹ค
โ—ฝ ์ด ์–ด๋…ธํ…Œ์ด์…˜์„ ์ปจํŠธ๋กค๋Ÿฌ ํด๋ž˜์Šค์— ์ ์šฉํ•˜๋ฉด, ๋ชจ๋“  ์š”์ฒญ ๋งคํ•‘ ๋ฉ”์†Œ๋“œ์—์„œ ๋ฐ˜ํ™˜๋˜๋Š” ๋ฐ์ดํ„ฐ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ JSON ํ˜•ํƒœ์˜ ๊ฐ์ฒด ๋ฐ์ดํ„ฐ๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค
โ—ฝ ๋”ฐ๋ผ์„œ ๊ฐ ๋ฉ”์†Œ๋“œ์— @ResponseBody๋ฅผ ๋ณ„๋„๋กœ ์ถ”๊ฐ€ํ•  ํ•„์š”๊ฐ€ ์—†๊ฒŒ ๋œ๋‹ค

๐Ÿ“˜ Entity์™€ DTO

๐Ÿ“– Entity

๐ŸŽˆ ํšŒ์› Entity

@Entity
@Getter @Setter
public class Member {
    @Id @GeneratedValue
    @Column(name = "member_id")
    private Long id;

    private String name;

    @Embedded
    private Address address;

    @OneToMany(mappedBy = "member")
    private List<Order> orders = new ArrayList<>();
}

โœ” @Entity์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ํ…Œ์ด๋ธ”๊ณผ ์ผ๋Œ€์ผ๋กœ ๋งค์นญ๋˜๋Š” ๊ฐ์ฒด ๋‹จ์œ„์ด๋ฉฐ, Entity ๊ฐ์ฒด์˜ ์ธ์Šคํ„ด์Šค ํ•˜๋‚˜๊ฐ€ ํ…Œ์ด๋ธ”์—์„œ ํ•˜๋‚˜์˜ ๋ ˆ์ฝ”๋“œ ๊ฐ’์„ ์˜๋ฏธํ•˜๊ฒŒ ๋œ๋‹ค
โœ” ๊ฐ์ฒด์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•œ ์œ ์ผํ•œ ํ‚ค ๊ฐ’์„ ๊ฐ€์ง€๋Š”๋ฐ ์ด๊ฒƒ์€ ํ…Œ์ด๋ธ” ์ƒ์˜ Primary Key์™€ ๊ฐ™์€ ์˜๋ฏธ๋ฅผ ๊ฐ€์ง€๋ฉฐ @Id๋กœ ํ‘œ๊ธฐ๋œ๋‹ค

๐Ÿ“– DTO

DTO(Data Transfer Object, ๋ฐ์ดํ„ฐ ์ „์†ก ๊ฐ์ฒด)๋ž€ ํ”„๋กœ์„ธ์Šค ๊ฐ„์— ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฐ์ฒด

๐ŸŽˆ ํšŒ์› ๋“ฑ๋ก API

1) Entity๋ฅผ Request Body์— ์ง์ ‘ ๋งคํ•‘

@RestController
@RequiredArgsConstructor
public class MemberApiController {
    private final MemberService memberService;

    @PostMapping("/api/v1/members")
    public CreateMemberResponse saveMemberV1(@RequestBody @Valid Member member) {
        Long id = memberService.join(member);
        return new CreateMemberResponse(id);
    }

    @Data
    static class CreateMemberResponse {
        private Long id;

        public CreateMemberResponse(Long id) {
            this.id = id;
        }
    }
}

โ—ฝ ์‹ค๋ฌด์—์„œ๋Š” ํšŒ์› Entity๋ฅผ ์œ„ํ•œ API๊ฐ€ ๋‹ค์–‘ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์ง€๋Š”๋ฐ, ํ•œ Entity์— ๊ฐ๊ฐ์˜ API๋ฅผ ์œ„ํ•œ ๋ชจ๋“  ์š”์ฒญ ์š”๊ตฌ์‚ฌํ•ญ์„ ๋‹ด๊ธฐ๋Š” ์–ด๋ ต๋‹ค
โ—ฝ Entity๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด API ์ŠคํŽ™์ด ๋ณ€ํ•œ๋‹ค
-> API ์š”์ฒญ ์ŠคํŽ™์— ๋งž์ถ”์–ด ๋ณ„๋„์˜ DTO๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›๋Š”๋‹ค

2) Entity ๋Œ€์‹ ์— DTO๋ฅผ RequestBody์— ๋งคํ•‘

@RestController
@RequiredArgsConstructor
public class MemberApiController {
    private final MemberService memberService;

    @PostMapping("/api/v2/members")
    public CreateMemberResponse saveMemberV2(@RequestBody @Valid CreateMemberRequest request) {
        Member member = new Member();
        member.setName(request.name);
        Long id = memberService.join(member);
        return new CreateMemberResponse(id);
    }

    @Data
    static class CreateMemberRequest {
        @NotEmpty
        private String name;
    }

    @Data
    static class CreateMemberResponse {
        private Long id;

        public CreateMemberResponse(Long id) {
            this.id = id;
        }
    }
}

โ—ฝ ์š”์ฒญ ๊ฐ’์œผ๋กœ Member ์—”ํ‹ฐํ‹ฐ ๋Œ€์‹ ์— ๋ณ„๋„์˜ DTO๋ฅผ ๋ฐ›๋Š”๋‹ค
โ—ฝ CreateMemberRequest๋ฅผ Member Entity ๋Œ€์‹ ์— RequestBody์™€ ๋งคํ•‘ํ•œ๋‹ค
โ—ฝ Entity๊ฐ€ ๋ณ€ํ•ด๋„ API ์ŠคํŽ™์ด ๋ณ€ํ•˜์ง€ ์•Š๋Š”๋‹ค

๐Ÿ“” JSON

โ—ฝ JSON(JavaScript Object Notation)์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅ/์ „์†ก ํ•  ๋•Œ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” ํ˜•์‹
โ—ฝ ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ ๊ฐ„์˜ ํ†ต์‹ ์—์„œ ์ฃผ๋กœ ๋งŽ์ด ์‚ฌ์šฉ๋จ
โ—ฝ ๊ฐ„๋‹จํ•œ ํ˜•์‹์„ ๊ฐ–๋Š” ๋ฌธ์ž์—ด(๋ฐ์ดํ„ฐ ๊ตํ™˜์— ์ฃผ๋กœ ์‚ฌ์šฉ)
โ—ฝ Key, Value ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง
โ—ฝ ๋ฌธ์ž์—ด, ์ˆซ์ž, ๋ฐฐ์—ด, ๋ถˆ๋ฆฌ์–ธ ๊ทธ๋ฆฌ๊ณ  ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์žˆ์Œ

๐Ÿ“– JSON ๊ตฌ์กฐ

1) JSON ๋ฐ์ดํ„ฐ๋Š” ์ด๋ฆ„๊ณผ ๊ฐ’์˜ ์Œ, key : value ํ˜•์‹์œผ๋กœ ๊ตฌ์„ฑ, ์ค‘๊ด„ํ˜ธ({})๋กœ ๋‘˜๋Ÿฌ์Œ“์•„ ํ‘œํ˜„

{ key : value }
ex) {"name": "์‹๋นต"}

2) JSON ๋ฐ์ดํ„ฐ๋Š” ์‰ผํ‘œ(,)๋กœ ๋‚˜์—ด

{
	"name": "์‹๋นต",
    "family": "์›ฐ์‹œ์ฝ”๊ธฐ",
    "age": 1,
    "weight": 2.14
}

๐Ÿ“– JSON ๋ฐ์ดํ„ฐ ํƒ€์ž…(datatype)

1) ์ˆซ์ž(number)
โ—ฝ ์ˆซ์ž๋Š” ์ •์ˆ˜ ๋˜๋Š” ๋ถ€๋™์†Œ์ˆ˜์—ฌ์•ผ ํ•จ. ํฐ ๋”ฐ์˜ดํ‘œ("")๋กœ ์•ˆ ๋ฌถ์Œ

{ "year" : 2024 }

2) ๋ฌธ์ž์—ด(string)
โ—ฝ ํฐ๋”ฐ์˜ดํ‘œ("")๋กœ ๋ฌถ์–ด์ค€๋‹ค

{ "name" : "kaeun" }

3) ๋ถˆ๋ฆฌ์–ธ(boolean)
โ—ฝ ์ฐธ : true, ๊ฑฐ์ง“ : false

{ "manager" : true }

4) ๊ฐ์ฒด(object)
โ—ฝ ๊ฐ์ฒด๋Š” JSON ๊ฐ์ฒด์™€ ๊ฐ™์€ ๊ทœ์น™์„ ๋”ฐ๋ผ์•ผ ํ•จ

{ "code" : {
	"HTML":"๊ธฐ๋ณธํ‹€",
    "CSS":"๋””์ž์ธ",
    "JS":"๋™์ž‘๊ฐ€๋Šฅ"
    }
}

5) ๋ฐฐ์—ด(array)
โ—ฝ ๋ฐฐ์—ด(array)์€ ๋Œ€๊ด„ํ˜ธ([])๋กœ ๋‘˜๋Ÿฌ์Œ“์•„ ํ‘œํ˜„. ๋˜ํ•œ, JSON ๋ฐฐ์—ด์€ ์‰ผํ‘œ(,)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ JSON ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋‹ค

{ "number" : ["์ผ", "์ด", "์‚ผ"] }

6) null
โ—ฝ null : ๊ณต๊ฐ„๋งŒ ์žˆ์„ ๋ฟ, ์•„๋ฌด๊ฒƒ๋„ ์—†๋Š” ์ƒํƒœ, 0๊ณผ๋Š” ๋‹ค๋ฅธ ๊ฐœ๋…

{ "point" : null }

7) JSON Array
โ—ฝ ์—ฌ๋Ÿฌ๊ฐœ์˜ JSON Object๋“ค์ด ๋ชจ์ธ ๊ฒƒ์ด JSON Array๋กœ ๋Œ€๊ด„ํ˜ธ๋กœ ๋‘˜๋Ÿฌ์‹ธ์ธ ๋ถ€๋ถ„

[{"id": 0, "name": "์‹๋นต"}, //0๋ฒˆ index
{"id": 1, "name": "๋‹จํŒฅ๋นต"}, //1๋ฒˆ index
{"id": 2, "name": "์†Œ๋ผ๋นต"}] //2๋ฒˆ index

๐Ÿ“š ์ฐธ๊ณ ์ž๋ฃŒ

๐Ÿ“– ์‹ค์ „! ์Šคํ”„๋ง ๋ถ€ํŠธ์™€ JPA ํ™œ์šฉ2 - API ๊ฐœ๋ฐœ๊ณผ ์„ฑ๋Šฅ ์ตœ์ ํ™”
๐Ÿ“– HTTP ๋ฉ”์„œ๋“œ ์ข…๋ฅ˜ & ์š”์ฒญ ํ๋ฆ„ ๐Ÿ’ฏ ์ด์ •๋ฆฌ
๐Ÿ“– REST API ๊ตฌ์„ฑ/ํŠน์ง• ์ด ์ •๋ฆฌ
๐Ÿ“– RESTful API ์ด๋ž€
๐Ÿ“– JSON์ด๋ž€? - JSON ๊ตฌ์กฐ, JSON ๋ฐ์ดํ„ฐ ํƒ€์ž…, JSON Array

profile
๊ฐ€๋ฟก์ด์˜ ๊ณต๋ถ€ ์ƒ์ž๐Ÿ“ฆ

0๊ฐœ์˜ ๋Œ“๊ธ€