์นดํ…Œ๊ณ ๋ฆฌ ์—†์Œ

RESTful API

camille: 2024. 10. 20. 17:41

๐Ÿ“• RESTfulAPI๋ผ๋Š” ๊ฒƒ์€?

API ์‹œ์Šคํ…œ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•œ ์•„ํ‚คํ…์ฒ˜ ์ค‘์— ๊ฐ€์žฅ ๋„๋ฆฌ ์‚ฌ์šฉ๋˜๋Š” ํ˜•์‹์ด๋‹ค.

Graphql,SOAP,GRPC,REST...etc

๐Ÿ“• Representational State Transfer

์›น์ƒ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์—ฌ๋Ÿฌ ๋ฆฌ์†Œ์Šค๋ฅผ HTTP URI๋กœ ํ‘œํ˜„ํ•˜๊ณ  ๊ทธ ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ํ–‰์œ„๋ฅผ HTTP Method๋กœ ์ •์˜ ํ•˜๋Š” ๋ฐฉ์‹. ์ฆ‰ ๋ฆฌ์†Œ์Šค(HTTP URI๋กœ ์ •์˜๋œ)๋ฅผ ์–ด๋–ป๊ฒŒ ํ•œ๋‹ค.(HTTP Method + Payloda)๋ฅผ ๊ตฌ์กฐ์ ์œผ๋กœ ๊น”๋”ํ•˜๊ฒŒ ํ‘œํ˜„ํ•œ๋‹ค.

์™œ restfulAPI๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š”๊ฐ€?

์ฝ”๋“œ์˜ ๋ณต์žก์„ฑ์ด ์˜ฌ๋ผ๊ฐ€๋ฉด์„œ ์ง๊ด€์ ์ธ ์ฝ”๋“œ๊ฐ€ ํ•„์š”์‹œ ๋˜๊ธฐ๋•Œ๋ฌธ์— JSON์„ ์‚ฌ์šฉํ•œ๋‹ค.

๐Ÿ’ก ๊ธฐ๋ณธ์ ์ธ ๋ฐฐ๊ฒฝ์ง€์‹
URI(Uniform Resource Identifier)

  • ํ•ด๋‹น์‚ฌ์ดํŠธ์˜ ํŠน์ • ์ž์›์˜ ์œ„์น˜๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์œ ์ผํ•œ ์ฃผ์†Œ

HTTP Method

  • HTTP request๊ฐ€ ์˜๋„ํ•˜๋Š” action์„ ์ •์˜ํ•œ ๊ฒƒ

Payload

  • HTTP request์—์„œ server๋กœ ๋ณด๋‚ด๋Š” ๋ฐ์ดํ„ฐ(body)

๐Ÿ“• RestfulAPI ์„ค๊ณ„๊ทœ์น™

  • URI ์ •๋ณด๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ํ‘œํ˜„ํ•ด์•ผํ•œ๋‹ค.

    • : resource๋Š” ๋ช…์‚ฌ๋ฅผ ์‚ฌ์šฉํ•˜์•ผ ํ•œ๋‹ค.**
      ex) GET/user/1 -> GET/users/1
  • resource์— ๋Œ€ํ•œ ํ–‰์œ„๋ฅผ HTTP Method(GET, POST, PUT, DELETE)๋กœ ํ‘œํ˜„ํ•œ๋‹ค.
    : URI์— HTTP Method๊ฐ€ ํฌํ•จ๋˜์„œ๋Š” ์•ˆ๋œ๋‹ค.
    ex) GET delete/user/1 -> DELETE/users/1

    :URI์— ๋™์‚ฌ๊ฐ€ ํฌํ•จ๋˜์„œ๋Š” ์•ˆ๋œ๋‹ค.
    ex) GET/user/show/1 -> GET/users/1
    ex) POST insert/users/2 -> POST/users/2

  • resource ์‚ฌ์ด์— ์—ฐ๊ด€ ๊ด€๊ณ„๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ
    : /๋ฆฌ์†Œ์Šค/๊ณ ์œ ID/๊ด€๊ณ„ ์žˆ๋Š” ๋ฆฌ์†Œ์Šค
    ex)GET/users/{user_id}/profile

  • ํŒŒ์ผ์˜ ๊ฒฝ์šฐ payload์˜ ํฌ๋ฉง์„ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•œ ํŒŒ์ผ ํ™•์žฅ์ž๋ฅผ URI์— ํฌํ•จ์‹œํ‚ค์ง€ ์•Š๋Š”๋‹ค.
    ex) GET user/1/profile-photo.jpg(X)
    ex) GET user/profile-photo (์ด๋•Œ, payload์˜ ํฌ๋ฉง์€ headers์— accept๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.)

๐Ÿ“• Path parameter

๋’ค์— ๋ฆฌ์Šคํฐ์Šค๋กœ ๋น„์–ด์žˆ๋˜ DB์•ˆ์— ๋ฐ์ดํ„ฐ๊ฐ€ ๋“ค์–ด๊ฐ€๋ฉด์„œ ๋ฌด๋†์•ฝ๊น ์ƒ๊ฐ•์ด ๋“ค์–ด๊ฐ€๊ฒŒ ๋œ๋‹ค. ์ˆ˜์ •์— ๊ด€๋ จ๋œ ๋ฉ”์†Œ๋“œ๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค. PATCH PUT ๋‘˜๋‹ค ์ˆ˜์ •์— ๊ด€๋ จ๋œ API

๐Ÿ“• PUT vs PATCH

PUT๊ณผ PATCH๋Š” ๋‘˜๋‹ค ๋ฐ์ดํ„ฐ ์ˆ˜์ •์„ ์œ„ํ•œ ๋ฉ”์„œ๋“œ์ด๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ์ด ๋‘๊ฐ€์ง€๋Š” ์–ด๋– ํ•œ ์ฐจ์ด์ ์ด ์žˆ์„๊นŒ?

  • PATCH, which is used to apply partial modifications to a resource
  • PUT method requests that the state of the target resource be created or replaced with the state defined by the representation enclosed in the request message payload

์˜ˆ์‹œ๋กœ, PUT์š”์ฒญ์‹œ์— ์š”์ฒญ์˜ ์ผ๋ถ€๋ถ„๋งŒ ๋ณด๋‚ธ๊ฒฝ์šฐ ๋‚˜๋จธ์ง€๋Š” default๊ฐ’์œผ๋กœ ์ˆ˜์ •๋˜๋Š” ๊ฒƒ์ด ์›์น™์ด๋‹ค. ๋”ฐ๋ผ์„œ ๋ฐ”๋€Œ์ง€ ์•Š๋Š” ์†์„ฑ๋„ ๋ชจ๋‘ ๋ณด๋‚ด์•ผํ•œ๋‹ค.

๋˜ ๋‹ค๋ฅธ ์˜ˆ์‹œ๋กœ, PUT HTTP ๋ฉ”์†Œ๋“œ๋กœ camille๋ผ๋Š” ์œ ์ €์˜ ๋‚˜์ด(age)๋ฅผ 15๋กœ ๋ณ€๊ฒฝํ•˜๊ณ ์ž ํ•  ๋•Œ ์ˆ˜์ •๋œ ๊ฐ’๋งŒ ๋ณด๋‚ผ ๊ฒฝ์šฐ ๋ณด๋‚ด์ง€ ์•Š์€ ๋ฐ์ดํ„ฐ๋Š” null๋กœ ๋ณ€๊ฒฝ๋˜์–ด ๋ฒ„๋ฆฐ๋‹ค.

PUT/users/1
{
    "age":15
}
HTTP/1.1 200 ok 
{
    "name" : null,
    "age" : 15 
}

๋”ฐ๋ผ์„œ PUT์š”์ฒญ์‹œ์—๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š” ๋ฐ์ดํ„ฐ๋ผ๋„ ๋ชจ๋‘ ์ „๋‹ฌ ํ•ด์•ผํ•œ๋‹ค.

PUT/users/1
{
      "name" : camille,
    "age": 15
}
HTTP/1.1 200 ok 
{
    "name" : camille,
    "age" : 15 
}

๊ทธ๋Ÿฌ๋‚˜ PATCH๋ฅผ ์ด์šฉํ•ด์„œ 'age'๋งŒ ๋ณ€๊ฒฝํ•˜๋Š” ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด, ์ƒˆ๋กญ๊ฒŒ ๋ฐ”๋€ ๋ถ€๋ถ„๋งŒ ๋ฐ˜์˜๋˜๋ฉฐ ๋‚˜๋จธ์ง€๋Š” ๊ธฐ์กด์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์œ ์ง€๋œ๋‹ค.

PATCH/users/1
{
    "age": 15
}
HTTP/1.1 200 ok 
{
    "name" : camille,
    "age" : 15 
}

๋”ฐ๋ผ์„œ ์ผ๋ถ€ ์ž์›์„ ์ˆ˜์ •ํ•  ๋•Œ๋Š” PATCH๋ฅผ ์ „์ฒด์ ์ธ ์ˆ˜์ •์ด ํ•„์š”ํ•  ๋•Œ๋Š” PUT ์„ ์ด์šฉํ•œ๋‹ค.

๐Ÿ“• GET vs POST

๐Ÿ’š Get

GET method๋Š” ํด๋ผ์ด์–ธํŠธ์—์„œ ์„œ๋ฒ„๋กœ ์–ด๋– ํ•œ ๋ฆฌ์†Œ์Šค๋กœ ๋ถ€ํ„ฐ ์ •๋ณด๋ฅผ ์š”์ฒญํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ๋ฉ”์„œ๋“œ์ด๋‹ค. ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ฑฐ๋‚˜(Read), ๊ฒ€์ƒ‰(Retrieve)ํ•  ๋•Œ์— ์‚ฌ์šฉ๋˜๋Š” method๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ,
GET์€ ์š”์ฒญ์„ ์ „์†กํ•  ๋•Œ URL ์ฃผ์†Œ ๋์— ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ํฌํ•จ๋˜์–ด ์ „์†ก๋˜๋ฉฐ, ์ด ๋ถ€๋ถ„์„ ์ฟผ๋ฆฌ ์ŠคํŠธ๋ง(QueryString)์ด๋ผ๊ณ  ๋งํ•œ๋‹ค.

ex) www.example-url.com/resources?name1=Camille&name2=Bbachon

์œ„ ์˜ˆ๋Š” ์•ž์„œ ๋งํ•œ ์ฟผ๋ฆฌ์ŠคํŠธ๋ง์„ ํฌํ•จํ•œ URL์ž…๋‹ˆ๋‹ค. ํŒŒ๋ผ๋ฏธํ„ฐ์ธ name1๊ณผ name2๋ฅผ ํ†ตํ•ด ๊ฐ’์„ ์ „๋‹ฌ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š”๋ฐ, ๋งŒ์•ฝ, ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ์ด๋ฉด &๋กœ ์—ฐ๊ฒฐํ•œ๋‹ค.

๋˜, GET ์š”์ฒญ์€ ์˜ค๋กœ์ง€ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์„ ๋•Œ๋งŒ ์‚ฌ์šฉ๋˜๊ณ  ์ˆ˜์ •ํ•  ๋•Œ๋Š” ์ „ํ˜€ ์‚ฌ์šฉ๋˜์ง€ ์•Š๊ธฐ ๋•จ๋ฌธ์— ๋ฐ์ดํ„ฐ ๋ณ€ํ˜•์˜ ์œ„ํ—˜์ด ์—†์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ˜€ GET ์š”์ฒญ์— ๋Œ€ํ•œ ๊ธฐํƒ€ ์ฐธ๊ณ  ์‚ฌํ•ญ

GET์€ ๋ถˆํ•„์š”ํ•œ ์š”์ฒญ์„ ์ œํ•œํ•˜๊ธฐ ์œ„ํ•ด ์š”์ฒญ์ด ์บ์‹œ๋  ์ˆ˜ ์žˆ๋‹ค.
๋”ฐ๋ผ์„œ, ํŒŒ๋ผ๋ฏธํ„ฐ์— ๋‚ด์šฉ์ด ๋…ธ์ถœ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃฐ ๋•Œ GET ์š”์ฒญ์„ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋œ๋‹ค.

  • GET ์š”์ฒญ์€ ๋ธŒ๋ผ์šฐ์ € ๊ธฐ๋ก์— ๋‚จ๋Š”๋‹ค.

  • ๋ถ๋งˆํฌ์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋ฐ์ดํ„ฐ ๊ธธ์ด์— ๋Œ€ํ•œ ์ œํ•œ์ด ์žˆ๋‹ค.
  • ์„ฑ๊ณต์‹œ, 200(Ok) HTTP ์‘๋‹ต ์ฝ”๋“œ๋ฅผ XML, JSON๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์—ฌ๋Ÿฌ ๋ฐ์ดํ„ฐ(html, txt๋“ฑ..), ์—ฌ๋Ÿฌ ํ˜•์‹์˜ ๋ฐ์ดํ„ฐ์™€ ํ•จ๊ป˜ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • GET ์š”์ฒญ์€ idempotentํ•˜๋‹ค.

๐Ÿ’š Post

POSTmethod๋Š” ๋ฆฌ์†Œ์Šค๋ฅผ ์ƒ์„ฑ/์—…๋ฐ์ดํŠธํ•˜๊ธฐ ์œ„ํ•ด ์„œ๋ฒ„์— ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.
GET๊ณผ ๋‹ฌ๋ฆฌ ์ „์†กํ•ด์•ผ๋  ๋ฐ์ดํ„ฐ๋ฅผ HTTP ๋ฉ”์„ธ์ง€์˜ Body์— ๋‹ด์•„์„œ ์ „์†กํ•˜๋Š”๋ฐ, ๊ทธ Body์˜ ํƒ€์ž…์€ ์š”์ฒญ ํ—ค๋”์˜ Content-Type์— ์š”์ฒญ ๋ฐ์ดํ„ฐ์˜ ํƒ€์ž…์„ ํ‘œ์‹œ ๋”ฐ๋ผ ๊ฒฐ์ • ๋œ๋‹ค.(POST๋กœ ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ๋Š” ํ•ด์•ผ ํ•œ๋‹ค!!)
HTTP ๋ฉ”์„ธ์ง€์˜ Body๋Š” ๊ธธ์ด์˜ ์ œํ•œ์—†์ด ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— POST ์š”์ฒญ์€ GET๊ณผ ๋‹ฌ๋ฆฌ ๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•  ์ˆ˜ ์žˆ๋‹ค.

์•ž์—์„œ ์–ธ๊ธ‰ํ–ˆ๋˜ ๊ฒƒ ์ฒ˜๋Ÿผ POST๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ Body๋กœ ์ „์†ก๋˜๊ณ , ๋‚ด์šฉ์ด ๋ˆˆ์— ๋ณด์ด์ง€ ์•Š์•„ GET๋ณด๋‹ค ๋ณด์•ˆ์ ์ธ ๋ฉด์—์„œ ์•ˆ์ „ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, POST ์š”์ฒญ๋„ ํฌ๋กฌ์˜ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ, Fiddler์™€ ๊ฐ™์€ ํˆด๋กœ ์š”์ฒญ ๋‚ด์šฉ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ์˜ ๊ฒฝ์šฐ์—๋Š” ๋ฐ˜๋“œ์‹œ ์•”ํ˜ธํ™”ํ•ด ์ „์†กํ•ด์•ผํ•œ๋‹ค.

๐Ÿ˜€ Post ์š”์ฒญ์— ๋Œ€ํ•œ ๊ธฐํƒ€ ์ฐธ๊ณ  ์‚ฌํ•ญ

POST ์š”์ฒญ์€ ์บ์‹œ๋˜์ง€ ์•Š๋Š”๋‹ค.

  • ๋ธŒ๋ผ์šฐ์ € ๊ธฐ๋ก์— ๋‚จ์•„ ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ๋ถ๋งˆํฌ์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • ๋ฐ์ดํ„ฐ ๊ธธ์ด์— ๋Œ€ํ•œ ์ œํ•œ์ด ์—†์Šต๋‹ˆ๋‹ค.
  • ์ž์› ์ƒ์„ฑ์€ 201(Created) HTTP ์‘๋‹ต ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  • Post ์š”์ฒญ์€ idempotentํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

idempotent๋ž€?

idempotent๋Š”์—ฐ์‚ฐ์„ ์—ฌ๋Ÿฌ ๋ฒˆ ์ ์šฉํ•˜๋”๋ผ๋„ ๊ฒฐ๊ณผ๊ฐ€ ๋‹ฌ๋ผ์ง€์ง€ ์•Š๋Š” ์„ฑ์งˆ์„ ์˜๋ฏธํ•œ๋‹ค.

"์—ฐ์‚ฐ์„ ์—ฌ๋Ÿฌ ๋ฒˆ ์ ์šฉํ•˜๋”๋ผ๋„ ๊ฒฐ๊ณผ๊ฐ€ ๋‹ฌ๋ผ์ง€์ง€ ์•Š๋Š” ์„ฑ์งˆ"

๋™์ผํ•œ ์—ฐ์‚ฐ์„ ์—ฌ๋Ÿฌ ๋ฒˆ ์ˆ˜ํ–‰ํ•˜๋”๋ผ๋„ ๋™์ผํ•œ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜ํƒ€๋‚˜์•ผ ํ•œ๋‹ค.

GET์€ Idempotent, POST๋Š” Non-idempotentํ•˜๊ฒŒ ์„ค๊ณ„๋˜์—ˆ๋‹ค.
์—ฌ๊ธฐ์„œ GET์ด Idempotentํ•˜๋„๋ก ์„ค๊ณ„๋˜์—ˆ๋‹ค๋Š” ๊ฒƒ์€ GET์œผ๋กœ ์„œ๋ฒ„์—๊ฒŒ ๋™์ผํ•œ ์š”์ฒญ์„ ์—ฌ๋Ÿฌ ๋ฒˆ ์ „์†กํ•˜๋”๋ผ๋„ ๋™์ผํ•œ ์‘๋‹ต์ด ๋Œ์•„์™€์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค. ๋˜, ์ด์— ๋”ฐ๋ผ GET์€ ์„ค๊ณ„์›์น™์— ๋”ฐ๋ผ ์„œ๋ฒ„์˜ ๋ฐ์ดํ„ฐ๋‚˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝ์‹œํ‚ค์ง€ ์•Š์•„์•ผ Idempotentํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ฃผ๋กœ ์กฐํšŒ๋ฅผ ํ•  ๋•Œ์— ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ๋ธŒ๋ผ์šฐ์ €์—์„œ ์›นํŽ˜์ด์ง€๋ฅผ ์—ด์–ด๋ณด๊ฑฐ๋‚˜ ๊ฒŒ์‹œ๊ธ€์„ ์ฝ๋Š” ๋“ฑ ์กฐํšŒ๋ฅผ ํ•˜๋Š” ํ–‰์œ„๋Š” GET์œผ๋กœ ์š”์ฒญํ•˜๊ฒŒ๋œ๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

๋ฐ˜์‘ํ˜•