๐Ÿ”จ[๊ฐœ๋ฐœ] RESTful API

manduยท2025๋…„ 5์›” 25์ผ

[๊ฐœ๋ฐœ]

๋ชฉ๋ก ๋ณด๊ธฐ
3/9

1. RESTful API๋ž€?

1.1. REST์˜ ์ •์˜์™€ ๊ธฐ๋ณธ ๊ฐœ๋…

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

1.2. REST์™€ SOAP ๋น„๊ต

  • SOAP(Simple Object Access Protocol)์€ XML(eXtensible Markup Language)์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” ํ”„๋กœํ† ์ฝœ๋กœ, RESTful API์™€ ๋น„๊ตํ•˜์—ฌ ๋ณต์žกํ•˜๊ณ  ๋ฌด๊ฒ๋‹ค๋Š” ํŠน์ง•์ด ์žˆ์Œ.
  • REST๋Š” HTTP ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•ด ์ž์›์— ์ ‘๊ทผํ•˜๋Š” ๋ฐฉ์‹์„ ๋”ฐ๋ฅด๋ฉฐ, ๊ฐ„๋‹จํ•˜๊ณ  ์ง๊ด€์ ์ž„.
  • SOAP๋Š” ๋ณด์•ˆ, ํŠธ๋žœ์žญ์…˜ ๋“ฑ์„ ์ œ๊ณตํ•˜์ง€๋งŒ REST๋Š” ๋” ๊ฐ„๊ฒฐํ•˜๊ณ  ์„ฑ๋Šฅ์ด ์šฐ์ˆ˜ํ•จ.

1.3. RESTful API์˜ ํŠน์ง•

  • ๋ฌด์ƒํƒœ์„ฑ(Stateless): ์„œ๋ฒ„๋Š” ํด๋ผ์ด์–ธํŠธ์˜ ์ƒํƒœ๋ฅผ ์ €์žฅํ•˜์ง€ ์•Š์Œ.
  • ์ž์› ๊ธฐ๋ฐ˜(URI): ๊ฐ ์ž์›์€ ๊ณ ์œ ํ•œ URI๋กœ ์‹๋ณ„๋จ.
  • ํ‘œํ˜„: ์ž์›์˜ ์ƒํƒœ๋Š” JSON(Most), XML ๋“ฑ์œผ๋กœ ํ‘œํ˜„๋จ.
  • HTTP ๋ฉ”์„œ๋“œ ํ™œ์šฉ: ์ž์›์— ๋Œ€ํ•œ ์ž‘์—…์€ GET, POST, PUT, DELETE ๋“ฑ์˜ HTTP ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์ˆ˜ํ–‰๋จ.
  • ์š”์ฒญ๊ณผ ์‘๋‹ต (Request and Response): ํด๋ผ์ด์–ธํŠธ๋Š” ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ , ์„œ๋ฒ„๋Š” ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•จ. ์š”์ฒญ์—๋Š” ๋ฉ”์„œ๋“œ, URI, ํ—ค๋”, ๋ฐ”๋”” ๋“ฑ์ด ํฌํ•จ๋˜๊ณ , ์‘๋‹ต์—๋Š” ์ƒํƒœ ์ฝ”๋“œ, ํ—ค๋”, ๋ฐ”๋””๊ฐ€ ํฌํ•จ๋จ.

2. RESTful API์˜ ๊ตฌ์„ฑ ์š”์†Œ

2.1. ์ž์›(Resource): URI

  • ๋ชจ๋“  ์ž์›์€ URI(Uniform Resource Identifier) ํ˜น์€ URL(Uniform Resource Location)์œผ๋กœ ์‹๋ณ„๋จ.
  • ๊ฐ ์ž์›์€ ๊ณ ์œ ํ•œ URI๋ฅผ ํ†ตํ•ด ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Œ.
  • e.g. /users๋Š” ๋ชจ๋“  ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๋‚˜ํƒ€๋‚ด๊ณ , /users/{id}๋Š” ํŠน์ • ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ๋‚˜ํƒ€๋ƒ„.

2.2. ํ–‰์œ„(Verb): HTTP ๋ฉ”์„œ๋“œ

  • POST(Create): ์ž์› ์ƒ์„ฑ
  • GET(Read): ์ž์› ์กฐํšŒ
  • PUT(Update): ์ž์› ์—…๋ฐ์ดํŠธ
  • DELETE(Delete): ์ž์› ์‚ญ์ œ
  • HEAD: Header ์ •๋ณด ์กฐํšŒ

2.3 ํ‘œํ˜„(Representationย ofย Resource)

  • Client๊ฐ€ ์ž์›์˜ ์ƒํƒœ(์ •๋ณด)์— ๋Œ€ํ•œ ์กฐ์ž‘์„ ์š”์ฒญํ•˜๋ฉด Server๋Š” ์ด์— ์ ์ ˆํ•œ ์‘๋‹ต(Representation)์„ ๋ณด๋ƒ„
  • ํ•˜๋‚˜์˜ ์ž์›์€ JSON, XML, TEXT, RSS ๋“ฑ ์—ฌ๋Ÿฌ ํ˜•ํƒœ์˜ Representation์œผ๋กœ ๋‚˜ํƒ€๋‚ด์–ด ์งˆ ์ˆ˜ ์žˆ์Œ.
  • JSONย ํ˜น์€ย XML๋ฅผย ํ†ตํ•ดย ๋ฐ์ดํ„ฐ๋ฅผย ์ฃผ๊ณ ย ๋ฐ›๋Š”ย ๊ฒƒ์ดย ์ผ๋ฐ˜์ ์ž„.

3. RESTful API ์„ค๊ณ„ ์›์น™

3.1. ๊ฐ„๊ฒฐํ•˜๊ณ  ๋ช…ํ™•ํ•œ URI ์„ค๊ณ„

  • RESTful API ์„ค๊ณ„์—์„œ URI๋Š” ์ž์›์„ ๋ช…ํ™•ํžˆ ์‹๋ณ„ํ•˜๊ณ  ์˜๋ฏธ ์žˆ๋Š” ๋ฐฉ์‹์œผ๋กœ ์ •์˜ํ•ด์•ผ ํ•จ.
  • /users์™€ ๊ฐ™์€ ๋ณต์žกํ•˜์ง€ ์•Š๊ณ  ์ง๊ด€์ ์ธ ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Œ.

3.2. HTTP ๋ฉ”์„œ๋“œ์˜ ์ ์ ˆํ•œ ์‚ฌ์šฉ

  • HTTP ๋ฉ”์„œ๋“œ๋Š” ์ž์›์— ๋Œ€ํ•œ ์ž‘์—…์„ ๋ช…ํ™•ํ•˜๊ฒŒ ์ •์˜ํ•˜๋Š” ์ค‘์š”ํ•œ ์š”์†Œ์ž„.
  • e.g. ๋ฐ์ดํ„ฐ ์กฐํšŒ๋Š” GET, ๋ฐ์ดํ„ฐ ์ƒ์„ฑ์€ POST, ์—…๋ฐ์ดํŠธ๋Š” PUT, ์‚ญ์ œ๋Š” DELETE๋ฅผ ์‚ฌ์šฉํ•จ.

3.3. ์ƒํƒœ ์ฝ”๋“œ(State Codes)์™€ ์—๋Ÿฌ ์ฒ˜๋ฆฌ

  • RESTful API๋Š” ์š”์ฒญ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ HTTP ์ƒํƒœ ์ฝ”๋“œ๋กœ ์ „๋‹ฌํ•จ.
  • e.g. 200๋ฒˆ๋Œ€ ์ฝ”๋“œ๋Š” ์„ฑ๊ณต, 400๋ฒˆ๋Œ€ ์ฝ”๋“œ๋Š” ํด๋ผ์ด์–ธํŠธ ์˜ค๋ฅ˜, 500๋ฒˆ๋Œ€ ์ฝ”๋“œ๋Š” ์„œ๋ฒ„ ์˜ค๋ฅ˜๋ฅผ ๋‚˜ํƒ€๋ƒ„.

3.4. ํ•„์ˆ˜ ํ—ค๋”(Header)์™€ ์ธ์ฆ(Authentication)

  • RESTful API๋Š” ์š”์ฒญ๊ณผ ์‘๋‹ต์— ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ํ—ค๋”์— ๋‹ด์•„ ์ „๋‹ฌํ•จ.
  • ๋˜ํ•œ, API์˜ ๋ณด์•ˆ์„ ์œ„ํ•ด ์ธ์ฆ๊ณผ ๊ถŒํ•œ ๋ถ€์—ฌ๋ฅผ ์ ์ ˆํžˆ ๊ตฌํ˜„ํ•ด์•ผ ํ•จ.

4. FastAPI๋กœ RESTful API ๊ตฌํ˜„ํ•˜๊ธฐ

4.1. FastAPI ์†Œ๊ฐœ ๋ฐ ์„ค์น˜

  • FastAPI๋Š” Python์„ ์‚ฌ์šฉํ•œ ๊ณ ์„ฑ๋Šฅ ์›น ํ”„๋ ˆ์ž„์›Œํฌ๋กœ, RESTful API๋ฅผ ์‰ฝ๊ณ  ๋น ๋ฅด๊ฒŒ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„๋จ.
    • pip install fastapi[all]
  • FastAPI ์„œ๋ฒ„๋ฅผ ์˜คํ”ˆํ•˜๋ ค๋ฉด WSGI (Web Server Gateway Interface)์„œ๋ฒ„, ํ˜น์€ ํ”„๋ก์‹œ ์„œ๋ฒ„๊ฐ€ ํ•„์š”ํ•จ
    • pip install uvicorn

WSGI (Web Server Gateway Interface)
WSGI๋Š” Python ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ์›น ์„œ๋ฒ„ ๊ฐ„์˜ ํ‘œ์ค€ ์ธํ„ฐํŽ˜์ด์Šค

  • ๋™๊ธฐ ๊ธฐ๋ฐ˜ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•  ๋•Œ ์ฃผ๋กœ ์‚ฌ์šฉ๋จ.
  • Flask๋‚˜ Django์™€ ๊ฐ™์€ ๋™๊ธฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์ž์ฃผ ์‚ฌ์šฉ๋จ.
  • WSGI ์„œ๋ฒ„๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์š”์ฒญ์„ ๋ฐ›์•„ ์›น ์„œ๋ฒ„๊ฐ€ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ํ˜•ํƒœ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์ „๋‹ฌํ•จ.
  • Gunicorn์ด๋‚˜ uWSGI ๊ฐ™์€ ์„œ๋ฒ„๊ฐ€ WSGI ์„œ๋ฒ„๋กœ ๋„๋ฆฌ ์‚ฌ์šฉ๋จ.

ํ”„๋ก์‹œ ์„œ๋ฒ„ (Proxy Server)
ํ”„๋ก์‹œ ์„œ๋ฒ„๋Š” ํด๋ผ์ด์–ธํŠธ์™€ ์‹ค์ œ ์„œ๋ฒ„ ์‚ฌ์ด์—์„œ ์š”์ฒญ๊ณผ ์‘๋‹ต์„ ์ค‘๊ณ„ํ•˜๋Š” ์„œ๋ฒ„

  • Nginx๋‚˜ Apache์™€ ๊ฐ™์€ ์›น ์„œ๋ฒ„๊ฐ€ ์ฃผ๋กœ ํ”„๋ก์‹œ ์„œ๋ฒ„๋กœ ์‚ฌ์šฉ๋จ.
  • ์ฃผ์š” ์—ญํ• :
    • ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ์„ ์‹ค์ œ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๋กœ ์ „๋‹ฌ.
    • ๋กœ๋“œ ๋ฐธ๋Ÿฐ์‹ฑ, ๋ณด์•ˆ, SSL ์ข…๋ฃŒ, ์บ์‹ฑ ๋“ฑ์˜ ์ž‘์—…์„ ์ฒ˜๋ฆฌ.
    • ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„ ๊ฐ„์˜ ํŠธ๋ž˜ํ”ฝ์„ ๊ด€๋ฆฌํ•˜๊ณ  ์ตœ์ ํ™”ํ•จ.

4.2. ์ฒซ ๋ฒˆ์งธ API ์ž‘์„ฑ

FastAPI๋ฅผ ์ด์šฉํ•ด ๊ฐ„๋‹จํ•œ API๋ฅผ ์ž‘์„ฑํ•˜๋Š” ์˜ˆ์ œ

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"message": "Hello, FastAPI!"}
uvicorn main:app --reload

4.3. GET, POST, PUT, DELETE ์˜ˆ์ œ

FastAPI๋Š” HTTP ๋ฉ”์„œ๋“œ๋ฅผ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•จ.

  • GET: /items๋กœ GET ์š”์ฒญ ์‹œ ์•„์ดํ…œ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜.
  • POST: /items๋กœ POST ์š”์ฒญ ์‹œ ์ƒˆ๋กœ์šด ์•„์ดํ…œ์„ ์ถ”๊ฐ€.
  • PUT: /items/{id}๋กœ PUT ์š”์ฒญ ์‹œ ํŠน์ • ์•„์ดํ…œ์„ ์—…๋ฐ์ดํŠธ.
  • DELETE: /items/{id}๋กœ DELETE ์š”์ฒญ ์‹œ ํŠน์ • ์•„์ดํ…œ์„ ์‚ญ์ œ.
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List

app = FastAPI()

# ์•„์ดํ…œ ๋ชจ๋ธ ์ •์˜
class Item(BaseModel):
    name: str
    description: str = None
    price: float
    tax: float = None

# ์•„์ดํ…œ ๋ฆฌ์ŠคํŠธ (์ž„์‹œ ์ €์žฅ์†Œ)
items = []

# 1. GET: /items๋กœ GET ์š”์ฒญ ์‹œ ์•„์ดํ…œ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜
@app.get("/items", response_model=List[Item])
def get_items():
    return items

# 2. POST: /items๋กœ POST ์š”์ฒญ ์‹œ ์ƒˆ๋กœ์šด ์•„์ดํ…œ์„ ์ถ”๊ฐ€
@app.post("/items", response_model=Item)
def create_item(item: Item):
    items.append(item)
    return item

# 3. PUT: /items/{id}๋กœ PUT ์š”์ฒญ ์‹œ ํŠน์ • ์•„์ดํ…œ์„ ์—…๋ฐ์ดํŠธ
@app.put("/items/{item_id}", response_model=Item)
def update_item(item_id: int, item: Item):
    if item_id >= len(items) or item_id < 0:
        raise HTTPException(status_code=404, detail="Item not found")
    items[item_id] = item
    return item

# 4. DELETE: /items/{id}๋กœ DELETE ์š”์ฒญ ์‹œ ํŠน์ • ์•„์ดํ…œ์„ ์‚ญ์ œ
@app.delete("/items/{item_id}")
def delete_item(item_id: int):
    if item_id >= len(items) or item_id < 0:
        raise HTTPException(status_code=404, detail="Item not found")
    deleted_item = items.pop(item_id)
    return {"message": "Item deleted", "item": deleted_item}
uvicorn main:app --reload

4.4. ๋ฐ์ดํ„ฐ ๊ฒ€์ฆ(Pydantic ๋ชจ๋ธ ์‚ฌ์šฉ)

FastAPI๋Š” Pydantic ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•ด ์š”์ฒญ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ์Œ.

from pydantic import BaseModel

class Item(BaseModel):
    name: str
    price: float
    description: str = None

# ์ด ๋ชจ๋ธ ํด๋ž˜์Šค๋Š” ์š”์ฒญ ๋ณธ๋ฌธ์—์„œ ๋ฐ›์€ ๋ฐ์ดํ„ฐ๊ฐ€ ์ •ํ™•ํ•œ ํƒ€์ž…์ธ์ง€, ํ•„์ˆ˜ ๊ฐ’์€ ์žˆ๋Š”์ง€, ๊ฐ ๊ฐ’์ด ์œ ํšจํ•œ์ง€ ๊ฒ€์‚ฌ

4.5. API ๋ฌธ์„œํ™”(Swagger UI)

  • FastAPI๋Š” Swagger UI๋ฅผ ํ†ตํ•ด API ๋ฌธ์„œ๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ด์คŒ.
  • /docs ๊ฒฝ๋กœ๋กœ ์ ‘๊ทผํ•˜๋ฉด API๋ฅผ ์‰ฝ๊ฒŒ ํ…Œ์ŠคํŠธํ•˜๊ณ  ๋ฌธ์„œํ™”ํ•  ์ˆ˜ ์žˆ์Œ.

Flask๋กœ RESTful API ๊ตฌํ˜„ํ•˜๊ธฐ

5.1. Flask ์†Œ๊ฐœ ๋ฐ ์„ค์น˜

Flask๋Š” ๊ฐ„๋‹จํ•˜๊ณ  ์œ ์—ฐํ•œ Python ์›น ํ”„๋ ˆ์ž„์›Œํฌ๋กœ, RESTful API๋ฅผ ๊ตฌ์ถ•ํ•˜๋Š” ๋ฐ ๋งŽ์ด ์‚ฌ์šฉ๋จ. pip install flask๋กœ ์„ค์น˜ํ•  ์ˆ˜ ์žˆ์Œ.

5.2. ๊ฐ€๋ฒผ์šด API ์ž‘์„ฑ

Flask๋กœ ๊ฐ„๋‹จํ•œ RESTful API๋ฅผ ์ž‘์„ฑํ•˜๋Š” ์˜ˆ์ œ

from flask import Flask, jsonify

app = Flask(__name__)

@app.route("/")
def hello():
    return jsonify({"message": "Hello, Flask!"})

if __name__ == "__main__":
    app.run(debug=True)
python app.py

์ด์ œ ์„œ๋ฒ„๊ฐ€ ์ผœ์กŒ๊ณ , http://127.0.0.1:5000์— ์ ‘์†ํ•˜๋ฉด,
์•„๋ž˜์™€ ๊ฐ™์ด ๋ฏธ๋ฆฌ ๋งŒ๋“  dict๊ฐ€ ๋œฌ๋‹ค.

5.3. Flask-restful ํ™•์žฅ ํŒจํ‚ค์ง€ ์‚ฌ์šฉํ•˜๊ธฐ

Flask๋Š” Flask-restful์ด๋ผ๋Š” ํ™•์žฅ ๋ชจ๋“ˆ์„ ํ†ตํ•ด RESTful API๋ฅผ ์‰ฝ๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Œ.

from flask import Flask
from flask_restful import Api, Resource

app = Flask(__name__)
api = Api(app)

# ๋ฆฌ์†Œ์Šค ์ •์˜
class Item(Resource):
    def get(self, item_id):
        return {"item": item_id}

# API ๋ฆฌ์†Œ์Šค ๋“ฑ๋ก
api.add_resource(Item, '/item/<int:item_id>')

if __name__ == "__main__":
    app.run(debug=True)
python app.py

์ด์ œ ์„œ๋ฒ„๊ฐ€ ์ผœ์กŒ๊ณ , http://127.0.0.1:5000/item/1004๋กœ ์ ‘์†ํ•˜๋ฉด,
์•„๋ž˜์™€ ๊ฐ™์ด ๋ฏธ๋ฆฌ ๋งŒ๋“  dict๊ฐ€ ๋œฌ๋‹ค.


6. RESTful API ๋ณด์•ˆ

6.1. ์ธ์ฆ(Authentication)๊ณผ ๊ถŒํ•œ ๋ถ€์—ฌ(Authorization)

  • RESTful API์—์„œ๋Š” ์‚ฌ์šฉ์ž์˜ ์ธ์ฆ๊ณผ ๊ถŒํ•œ ๋ถ€์—ฌ๊ฐ€ ํ•„์ˆ˜์ ์ž„.
  • JWT(JSON Web Token)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ API์˜ ์ธ์ฆ์„ ์ฒ˜๋ฆฌํ•จ.
  • ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ๋Š” SSL ์ธ์ฆ(Secure Sockets Layer) ๋˜๋Š” TLS ์ธ์ฆ(Transport Layer Security)์„ ์ ์šฉํ•˜๋Š” ๊ฒƒ์ด ํ•„์š”ํ•จ

6.2. JWT(JSON Web Token)์ด๋ž€?

  • JWT๋Š” API์—์„œ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์ž„.
  • JWT๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์„ธ์…˜์„ ์„œ๋ฒ„์—์„œ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๊ณ ๋„ ์‚ฌ์šฉ์ž ์ธ์ฆ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Œ.
  • JWT๋Š” ํ—ค๋”(Header), ํŽ˜์ด๋กœ๋“œ(Payload), ์„œ๋ช…(Signature) ์„ธ ๋ถ€๋ถ„์œผ๋กœ ๊ตฌ์„ฑ๋จ.
  1. Header (ํ—ค๋”):

    • JWT์˜ ์ฒซ ๋ฒˆ์งธ ๋ถ€๋ถ„์€ ํ—ค๋”๋กœ, ํ† ํฐ์˜ ํƒ€์ž…(์ผ๋ฐ˜์ ์œผ๋กœ JWT)๊ณผ ์„œ๋ช… ์•Œ๊ณ ๋ฆฌ์ฆ˜(์˜ˆ: HMAC SHA256, RSA ๋“ฑ)์„ ์ง€์ •.
    • e.g {"alg": "HS256", "typ": "JWT"}
  2. Payload (ํŽ˜์ด๋กœ๋“œ):

    • ํŽ˜์ด๋กœ๋“œ์—๋Š” ์ „์†กํ•  ์ •๋ณด๊ฐ€ ๋“ค์–ด ์žˆ์Œ.

    • ์ด ์ •๋ณด๋Š” ํด๋ ˆ์ž„(claims)์ด๋ผ๊ณ  ํ•˜๋ฉฐ, ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ์„ ๋ฐ›์€ ํ›„ ์„œ๋ฒ„์—์„œ ์–ด๋–ค ์ •๋ณด๊ฐ€ ํ•„์š”ํ•œ์ง€ ํฌํ•จ.

    • e.g. ์‚ฌ์šฉ์ž ID, ์—ญํ• (role), ๋งŒ๋ฃŒ ์‹œ๊ฐ„(expiration) ๋“ฑ์ด ํฌํ•จ๋  ์ˆ˜ ์žˆ์Œ

    • ํด๋ ˆ์ž„์€ ํฌ๊ฒŒ ์„ธ ๊ฐ€์ง€๋กœ ๋ถ„๋ฅ˜:

      • ๋“ฑ๋ก๋œ ํด๋ ˆ์ž„(Registered claims): JWT์—์„œ ์ •์˜๋œ ๊ธฐ๋ณธ ํด๋ ˆ์ž„(์˜ˆ: sub, iat, exp ๋“ฑ)
      • ๊ณต๊ฐœ ํด๋ ˆ์ž„(Public claims): ์‹œ์Šคํ…œ์—์„œ ์ž์œ ๋กญ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํด๋ ˆ์ž„
      • ๋น„๊ณต๊ฐœ ํด๋ ˆ์ž„(Private claims): ๋‘ ์‹œ์Šคํ…œ ๊ฐ„์— ํ•ฉ์˜๋œ ๋ฐ์ดํ„ฐ
    • e.g. {"sub": "1234567890", "name": "John Doe", "iat": 1516239022}

  3. Signature (์„œ๋ช…):

    • ์„œ๋ช…์€ ํ—ค๋”์™€ ํŽ˜์ด๋กœ๋“œ๊ฐ€ ๋ณ€์กฐ๋˜์ง€ ์•Š์•˜์Œ์„ ํ™•์ธํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ.
    • ์„œ๋ช…์€ header์™€ payload๋ฅผ ๋น„๋ฐ€ ํ‚ค(secret key)์™€ ํ•จ๊ป˜ ์„œ๋ช… ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•ด ์•”ํ˜ธํ™”ํ•˜์—ฌ ์ƒ์„ฑ
    • e.g. HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload), secret_key)

6.3 JWT์˜ ์‚ฌ์šฉ ํ๋ฆ„

  1. ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธ:

    • ์‚ฌ์šฉ์ž๊ฐ€ ์„œ๋ฒ„์— ๋กœ๊ทธ์ธํ•  ๋•Œ, ์„œ๋ฒ„๋Š” ์‚ฌ์šฉ์ž์˜ ์ธ์ฆ ์ •๋ณด๋ฅผ ํ™•์ธํ•˜๊ณ  JWT๋ฅผ ์ƒ์„ฑ.
    • ์ด JWT๋Š” ์„œ๋ฒ„๊ฐ€ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  2. JWT ์ €์žฅ:

    • ํด๋ผ์ด์–ธํŠธ๋Š” ๋ฐ›์€ JWT๋ฅผ ์ €์žฅํ•˜๊ณ , ์ดํ›„ ์„œ๋ฒ„์™€์˜ ํ†ต์‹ ์—์„œ ์ด ํ† ํฐ์„ HTTP ํ—ค๋”์— ํฌํ•จํ•˜์—ฌ ๋ณด๋ƒ„
  3. JWT ์ „์†ก:

    • ํด๋ผ์ด์–ธํŠธ๋Š” ์„œ๋ฒ„๋กœ ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ Authorization ํ—ค๋”์— Bearer์™€ ํ•จ๊ป˜ JWT๋ฅผ ํฌํ•จ.
    • e.g. Authorization: Bearer <JWT>
  4. ์„œ๋ฒ„์—์„œ JWT ๊ฒ€์ฆ:

    • ์„œ๋ฒ„๋Š” ๋ฐ›์€ JWT๋ฅผ ๊ฒ€์ฆํ•˜์—ฌ, ์œ ํšจํ•œ ํ† ํฐ์ธ์ง€, ๋ณ€์กฐ๋˜์ง€ ์•Š์•˜๋Š”์ง€, ๋งŒ๋ฃŒ๋˜์ง€๋Š” ์•Š์•˜๋Š”์ง€๋ฅผ ํ™•์ธ.
    • ์œ ํšจํ•œ ํ† ํฐ์ด๋ผ๋ฉด ์„œ๋ฒ„๋Š” ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

6.4. API Rate Limiting๊ณผ CORS ์„ค์ •

  • API์˜ ๋‚จ์šฉ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด Rate Limiting์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Œ.
  • ๋˜ํ•œ, CORS(Cross-Origin Resource Sharing)๋ฅผ ์„ค์ •ํ•˜์—ฌ ํŠน์ • ๋„๋ฉ”์ธ๋งŒ API์— ์ ‘๊ทผํ•˜๋„๋ก ์ œํ•œํ•  ์ˆ˜ ์žˆ์Œ.

profile
๋งŒ๋‘๋Š” ๋ชฉ๋ง๋ผ

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