[Spring Boot - ๐ŸฑPetClinic๐Ÿถ] 7. REST API ๋ถ„์„๐Ÿ”

์‘ค๋ฐยท2023๋…„ 4์›” 17์ผ

[Spring Boot - ๐ŸฑPetClinic๐Ÿถ]

๋ชฉ๋ก ๋ณด๊ธฐ
7/11

๐Ÿš€ REST API๋ž€?

REST API์˜ REST๋Š” Representational State Transfer์˜ ์•ฝ์ž๋กœ API ์ž‘๋™ ๋ฐฉ์‹์— ๋Œ€ํ•œ ์กฐ๊ฑด์„ ๋ถ€๊ณผํ•˜๋Š” ์†Œํ”„ํŠธ์›จ์–ด ์•„ํ‚คํ…์ฒ˜๋‹ค. REST ์•„ํ‚คํ…์ฒ˜ ์Šคํƒ€์ผ์˜ ์›์น™์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • ๊ท ์ผํ•œ ์ธํ„ฐํŽ˜์ด์Šค(Uniform)
    URI๋กœ ์ง€์ •ํ•œ ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ์กฐ์ž‘์„ ํ†ต์ผ๋˜๊ณ  ํ•œ์ •์ ์ธ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์ˆ˜ํ–‰
  • ๋ฌด์ƒํƒœ(Stateless)
    ์ž‘์—…์„ ์œ„ํ•œ ์ƒํƒœ์ •๋ณด๋ฅผ ๋”ฐ๋กœ ์ €์žฅํ•˜๊ณ  ๊ด€๋ฆฌํ•˜์ง€ ์•Š์Œ, ๋‹จ์ˆœํžˆ ๋“ค์–ด์˜ค๋Š” ์š”์ฒญ๋งŒ์„ ์ฒ˜๋ฆฌ
  • ๊ณ„์ธตํ™” ์‹œ์Šคํ…œ
    ๋‹ค์ค‘ ๊ณ„์ธต์œผ๋กœ ๊ตฌ์„ฑ๋  ์ˆ˜ ์žˆ์Œ
  • ์บ์‹œ ๊ฐ€๋Šฅ์„ฑ(Cacheable)
    HTTP๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— HTTP๊ฐ€ ๊ฐ€์ง„ ์บ์‹ฑ ๊ธฐ๋Šฅ ์ ์šฉ ๊ฐ€๋Šฅ(Last-Modified ํƒœ๊ทธ๋‚˜ E-Tag ์ด์šฉ)
  • ์˜จ๋””๋ฉ˜๋“œ ์ฝ”๋“œ
    ์„œ๋ฒ„๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ฝ”๋“œ๋ฅผ ํด๋ผ์ด์–ธํŠธ์— ์ „์†กํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ ๊ธฐ๋Šฅ์„ ์ผ์‹œ์ ์œผ๋กœ ํ™•์žฅํ•˜๊ฑฐ๋‚˜ ์‚ฌ์šฉ์ž ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Œ
  • Server-Client ๊ตฌ์กฐ
    ์„œ๋ฒ„ ์ธก์—์„œ๋Š” API ์ œ๊ณต, ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ๋Š” ์‚ฌ์šฉ์ž ์ธ์ฆ, ์ปจํ…์ŠคํŠธ(๋กœ๊ทธ์ธ, ์„ธ์…˜ ์ •๋ณด) ๋“ฑ์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ตฌ์กฐ๋กœ ๊ฐ์ž์˜ ์—ญํ• ์ด ๋ถ„๋ฆฌ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ์ž์˜ ๊ฐœ๋ฐœ ๋‚ด์šฉ์ด ๋ช…ํ™•ํ•ด์ง€๊ณ  ์„œ๋กœ๊ฐ„์˜ ์˜์กด์„ฑ์ด ๋‚ฎ์•„์ง

REST API๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ™•์žฅ์„ฑ, ์œ ์—ฐ์„ฑ, ๋…๋ฆฝ์„ฑ ์žˆ๋Š” ํ†ต์‹ ์ด ๊ฐ€๋Šฅํ•ด์ง„๋‹ค.

๐Ÿ“‹ REST API ๋””์ž์ธ

RESTfulํ•œ ์„ค๊ณ„๋ฅผ ์œ„ํ•ด์„œ๋Š” ๋‹ค์Œ์˜ ๋‘ ๊ฐ€์ง€๋ฅผ ์ง€์ผœ์ค˜์•ผ ํ•œ๋‹ค.

  • URI๋Š” ์ •๋ณด์˜ ์ž์›์„ ํ‘œํ˜„ํ•ด์•ผ ํ•œ๋‹ค.
    • '/'๋Š” ๊ณ„์ธต๊ด€๊ณ„๋ฅผ ๋‚˜ํƒ€๋‚ผ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค
    • ๋งˆ์ง€๋ง‰ ๋ฌธ์ž๋กœ '/'๋ฅผ ํฌํ•จํ•˜์ง€ ์•Š๋Š”๋‹ค.
    • '-'๋Š” ๊ฐ€๋…์„ฑ์„ ๋†’์ด๋Š”๋ฐ ์‚ฌ์šฉํ•˜๊ณ , '_'๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.
    • URI ๊ฒฝ๋กœ์—๋Š” ์†Œ๋ฌธ์ž๋งŒ ์‚ฌ์šฉํ•œ๋‹ค.
    • ํŒŒ์ผ ํ™•์žฅ์ž๋Š” URI์— ํฌํ•จ์‹œํ‚ค์ง€ ์•Š๋Š”๋‹ค. (Accept header ์‚ฌ์šฉ)
  • ์ž์›์— ๋Œ€ํ•œ ํ–‰์œ„๋Š” HTTP Method(POST, GET, PUT, DELETE)๋กœ ํ‘œํ˜„ํ•œ๋‹ค.
MethodRole
POST๋ฆฌ์†Œ์Šค ์ƒ์„ฑ(Create)
GET๋ฆฌ์†Œ์Šค ์š”์ฒญ(Read)
PUT๋ฆฌ์†Œ์Šค ์ˆ˜์ •(Update)
DELETE๋ฆฌ์†Œ์Šค ์‚ญ์ œ(Delete)

๐Ÿšฅ HTTP ์‘๋‹ต ์ƒํƒœ ์ฝ”๋“œ

์š”์ฒญ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋กœ ์„œ๋ฒ„ ์ธก์—์„œ ํด๋ผ์ด์–ธํŠธ ์ธก์œผ๋กœ ๋ณด๋‚ด๋Š” ์‘๋‹ต ์ƒํƒœ ์ฝ”๋“œ, ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ์— ๋”ฐ๋ผ ์•Œ๋งž์€ ์‘๋‹ต ์ฝ”๋“œ๋ฅผ ๋ณด๋‚ธ๋‹ค.

์ƒํƒœ์ฝ”๋“œ๋‚ด์šฉ
200 ๐ŸŸข์š”์ฒญ์„ ์ •์ƒ์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•จ
201 ๐ŸŸข๋ฆฌ์†Œ์Šค ์ƒ์„ฑ ์š”์ฒญ์„ ์ •์ƒ์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•จ
301 ๐ŸŸ URI ๋ณ€๊ฒฝ(Location header์— ๋ณ€๊ฒฝ๋œ URI ์ ์–ด์ค˜์•ผํ•จ.)
400 ๐Ÿ”ด๋ถ€์ ์ ˆํ•œ ์š”์ฒญ
401 ๐Ÿ”ด์ธ์ฆ๋˜์ง€ ์•Š์€ ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ
403 ๐Ÿ”ด์‘๋‹ตํ•˜๊ณ  ์‹ถ์ง€ ์•Š์€ ์š”์ฒญ(403๋ณด๋‹จ 400์ด๋‚˜ 404 ์‚ฌ์šฉ์„ ๊ถŒํ•จ)
404 ๐Ÿ”ด์š”์ฒญํ•œ ๋ฆฌ์†Œ์Šค๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Œ
405 ๐Ÿ”ด์‚ฌ์šฉ ๋ถˆ๊ฐ€๋Šฅํ•œ Method ์‚ฌ์šฉ
500 ๐Ÿ”ด์„œ๋ฒ„์— ๋ฌธ์ œ๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ ์‚ฌ์šฉ(Runtime Exception ๋“ฑ)

๐Ÿถ Pet Clinic URI ๋ถ„์„

์š”์ฒญ URI๋Š” ๊ฐ ๋„๋ฉ”์ธ๋ณ„ Controller์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค.

  • WelcomeController : index ํŽ˜์ด์ง€ ์š”์ฒญ
MethodURI์„ค๋ช…
GET/index ํŽ˜์ด์ง€ ์š”์ฒญ
  • OwnerController : onwer ๊ด€๋ จ ์กฐํšŒ/์ถ”๊ฐ€ ์š”์ฒญ
MethodURI์„ค๋ช…
GET/owners/newowner ์ถ”๊ฐ€ ํŽ˜์ด์ง€ ์š”์ฒญ
POST/owners/newowner ์ถ”๊ฐ€ ์š”์ฒญ
GET/owners/findowner ์ฐพ๊ธฐ ํŽ˜์ด์ง€ ์š”์ฒญ
GET/owners/owner ๋ฆฌ์ŠคํŠธ ํŽ˜์ด์ง€ ์š”์ฒญ
GET/owners/{ownerId}/editowner ์ˆ˜์ • ํŽ˜์ด์ง€ ์š”์ฒญ
POST/owners/{ownerId}/editowner ์ˆ˜์ • ์š”์ฒญ
GET/owners/{ownerId}owner ์ƒ์„ธ์ •๋ณด ํŽ˜์ด์ง€ ์š”์ฒญ
  • PetController : pet ๊ด€๋ จ ์กฐํšŒ/์ถ”๊ฐ€ ์š”์ฒญ
MethodURI(/owners/{ownerId} + )์„ค๋ช…
GET/pets/newpet ์ถ”๊ฐ€ ํŽ˜์ด์ง€ ์š”์ฒญ
POST/pets/newpet ์ถ”๊ฐ€ ์š”์ฒญ
GET/pets/{petId}/editpet ์ˆ˜์ • ํŽ˜์ด์ง€ ์š”์ฒญ
POST/pets/{petId}/editpet ์ˆ˜์ • ์š”์ฒญ
  • VisitController : visit ๊ด€๋ จ ์กฐํšŒ/์ถ”๊ฐ€ ์š”์ฒญ
MethodURI์„ค๋ช…
GET/owners/{ownerId}/pets/{petId}/visits/newvisit ์ถ”๊ฐ€ ํŽ˜์ด์ง€ ์š”์ฒญ
POST/owners/{ownerId}/pets/{petId}/visits/newvisit ์ถ”๊ฐ€ ์š”์ฒญ
  • VetController : vet ๊ด€๋ จ ์กฐํšŒ ์š”์ฒญ
MethodURI์„ค๋ช…
GET/vets.htmlvet ๋ชฉ๋ก ์กฐํšŒ ํŽ˜์ด์ง€ ์š”์ฒญ
GET/vetsvet ๋ฆฌ์ŠคํŠธ ์š”์ฒญ
  • CrashController : ์˜ค๋ฅ˜ํŽ˜์ด์ง€ ์š”์ฒญ
MethodURI์„ค๋ช…
GET/oups์˜ค๋ฅ˜ ํŽ˜์ด์ง€ ์š”์ฒญ

โ“ PUT vs POST

Pet Clinic์˜ URI ๋ถ„์„์„ ํ•˜๋‹ค ๋ณด๋‹ˆ CRUD๋ฅผ ์œ„ํ•ด POST/GET/PUT/DELETE๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ–ˆ๋Š”๋ฐ POST์™€ GET๋งŒ ์‚ฌ์šฉํ•˜๊ณ  PUT๊ณผ DELETE๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜๋‹ค. DELETE์•ผ ๊ธฐ๋Šฅ ๊ตฌํ˜„์ƒ ์“ฐ์ด์ง€ ์•Š์•„์„œ ์—†๋‹ค ์น˜๋”๋ผ๋„ ์ˆ˜์ •์„ ์œ„ํ•ด PUT์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์ด ์ดํ•ด๊ฐ€ ๊ฐ€์ง€ ์•Š์•„ ์ฐพ์•„๋ดค๋‹ค.

PUT์€ ์ž์›์ด ์กด์žฌํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ '์ƒ์„ฑ', ์กด์žฌํ•  ๊ฒฝ์šฐ '์ˆ˜์ •'ํ•˜๋Š” ๋ฐฉ์‹์ด๊ณ , POST๋Š” ์ž์›์˜ '์ƒ์„ฑ'์„ ์œ„ํ•œ ๋ฐฉ์‹์ด๋‹ค. PUT๊ณผ POST์˜ ๊ฐ€์žฅ ํฐ ์ฐจ์ด์ ์€ ๋ฉฑ๋“ฑ(idempotent)์— ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค. ๋ฉฑ๋“ฑ์„ฑ์„ ์ˆ˜์‹์œผ๋กœ ํ‘œํ˜„ํ•˜์ž๋ฉด 'f(x) = f(f(x))'๋‹ค. ๋ช‡ ๋ฒˆ์„ ๋ฐ˜๋ณตํ•ด๋„ ๊ฒฐ๊ณผ๊ฐ€ ๊ฐ™๋‹ค๋Š” ์˜๋ฏธ๋‹ค. PUT์€ ๋ฉฑ๋“ฑํ•˜๊ณ  POST๋Š” ๋ฉฑ๋“ฑํ•˜์ง€ ์•Š๋‹ค. PUT์€ ๋ช‡ ๋ฒˆ์„ ์‹œ๋„ํ•ด๋„ ๊ฒฐ๊ณผ๊ฐ€ ๊ฐ™์ง€๋งŒ, POST๋Š” ์‹œ๋„ํ•  ๋•Œ๋งˆ๋‹ค ๊ฒฐ๊ณผ๊ฐ€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค. ๋˜‘๊ฐ™์€ ์„ธ ๋ฒˆ์˜ ์š”์ฒญ์„ ์„œ๋ฒ„์— ์ „์†กํ•œ๋‹ค๊ณ  ํ•  ๋•Œ, PUT์€ ์„œ๋ฒ„์— ์š”์ฒญ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๊ฐ€ ์—†๋‹ค๊ณ  ํ•  ๋•Œ ์ฒ˜์Œ์€ ์ƒ์„ฑ, ๋‚˜๋จธ์ง€ ๋‘ ๋ฒˆ์€ ์ˆ˜์ • ์ฒ˜๋ฆฌ๋ฅผ ํ•  ๊ฒƒ์ด๋‹ค. ๋ฐ˜๋ฉด POST๋Š” ์„ธ ๋ฒˆ์˜ ์š”์ฒญ ๋ชจ๋‘ ์ƒ์„ฑ ์ฒ˜๋ฆฌ๋ฅผ ํ•œ๋‹ค๋Š” ์ ์—์„œ ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค.

์ด๊ฒƒ์€ ์ด๋ก ์ ์ธ ์–˜๊ธฐ๊ณ , ๊ทธ๋ž˜์„œ ์™œ 'PUT์œผ๋กœ ๋„˜๊ฒจ์•ผ ํ•  ๊ฒƒ ๊ฐ™์€๋ฐ POST ๋ฐฉ์‹์œผ๋กœ ๋„˜๊ธฐ๋А๋ƒ'์— ๋Œ€ํ•ด ์ฐพ์•„๋ดค๋‹ค. ์ˆ˜์ •์„ ์œ„ํ•œ ์š”์ฒญ ์ „์†ก ๋ฐฉ์‹์€ PUT, PATCH, POST ์„ธ ๊ฐ€์ง€๋กœ ๋ณผ ์ˆ˜ ์žˆ๋Š”๋ฐ, PUT์€ ์ˆ˜์ •๋ณด๋‹ค๋Š” ๊ต์ฒด(Replace)์— ๋” ๊ฐ€๊นŒ์šด ๊ฒƒ ๊ฐ™๋‹ค. ๋ถ€๋ถ„ ์ˆ˜์ •์„ ์œ„ํ•ด์„œ๋Š” PATCH์™€ POST๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ PATCH๋ฅผ ์‚ฌ์šฉํ•˜๊ธด ๊นŒ๋‹ค๋กญ๊ธฐ ๋•Œ๋ฌธ์—(safe ํ•˜์ง€ ์•Š๊ณ  idempotent ํ•˜์ง€๋„ ์•Š์€ ๋ฐฉ์‹, ์‹คํ–‰์— ๋”ฐ๋ผ ๊ฒฐ๊ณผ๊ฐ€ ๋ฐ”๋€” ์ˆ˜ ์žˆ์Œ, E-Tag์™€ ๋น„๋กฏํ•œ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๊ณ ๋ คํ•ด์•ผํ•จ) ์ฃผ๋กœ ์ž์›์˜ ๋ถ€๋ถ„ ์ˆ˜์ •์„ ์œ„ํ•ด์„œ๋Š” POST๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

์—ฌ๋Ÿฌ ๊ธ€์—์„œ ์„ค๋ช…ํ•  ๋•Œ๋Š” POST๊ฐ€ ์ƒ์„ฑ์„ ๋‹ด๋‹นํ•œ๋‹ค๊ณ ๋Š” ํ–ˆ์ง€๋งŒ ์‹ค์ œ๋กœ๋Š” ์ƒ์„ฑ๊ณผ ์ˆ˜์ •์— ๋ชจ๋‘ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค. (ํŠน์ •ํ•œ ์ƒํ™ฉ์—์„œ๋งŒ PUT์„ ์‚ฌ์šฉํ•˜๊ณ  ๋ณดํ†ต ์šฐ๋ฆฌ๊ฐ€ ์ƒ๊ฐํ•˜๋Š” ์ผ๋ถ€ ์ˆ˜์ •์˜ ๊ฒฝ์šฐ๋Š” POST๋ฅผ ์“ฐ๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ธ ๊ฒƒ ๊ฐ™๋‹ค.) Pet Clinic์—์„œ๋„ ์ „์ฒด ์ˆ˜์ •์ด ์•„๋‹Œ ์ผ๋ถ€๋งŒ ์ˆ˜์ •ํ•˜๊ธฐ ๋•Œ๋ฌธ์— PUT์ด ์•„๋‹Œ POST ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค.

๐Ÿงฉ ๋งˆ๋ฌด๋ฆฌ

๊ฐ ์š”์ฒญ URI์— ๋”ฐ๋ผ ์ •ํ•ด์ง„ ์ผ๋ จ์˜ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒŒ ์„œ๋ฒ„์˜ ์—ญํ• ์ด๋‹ค. ์ด ์š”์ฒญ URI๋ฅผ ์–ด๋–ป๊ฒŒ ๊ตฌ์„ฑํ•  ๊ฒƒ์ธ์ง€๊ฐ€ Backend์˜ ํ•ต์‹ฌ์ด์ง€ ์•Š์„๊นŒ? ์ผ๋‹จ ์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ์„œ๋ฒ„๋กœ ๋“ค์–ด์˜ฌ ์ˆ˜ ์žˆ๋Š” ์š”์ฒญ์˜ ์ข…๋ฅ˜์— ๋Œ€ํ•œ ๋‚ด์šฉ์„ ๋‹ค๋ค˜๋‹ค. ๋‹ค์Œ ๊ธ€์—์„œ๋Š” ๋“ค์–ด์˜จ ์ด ์š”์ฒญ๋“ค์ด ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌ๋˜๋Š”์ง€์— ๋Œ€ํ•ด ์ปจํŠธ๋กค๋Ÿฌ๋ณ„๋กœ ๋‹ค๋ฃฐ ์˜ˆ์ •์ด๋‹ค. REST API์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์ฐธ๊ณ  ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ•˜๋ฉด ๋œ๋‹ค.

[์ฐธ๊ณ ]

REST API ์„ค๋ช… -
https://aws.amazon.com/ko/what-is/restful-api/
https://meetup.nhncloud.com/posts/92
PUT vs POST -
https://repo.yona.io/doortts/blog/issue/12
https://www.keycdn.com/support/put-vs-post
http://1ambda.github.io/javascripts/rest-api-put-vs-post/

profile
๊ฐœ๋ฐœ์ž์ง€๋ง์ƒ

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