๐Ÿ“ฆ FastAPI์—์„œ์˜ Request์™€ Response ์™„๋ฒฝ ์ดํ•ด

๐Ÿ•’ ์•ฝ 2๋ถ„ ์ฝ๋Š” ๋ฐ ์†Œ์š”๋ฉ๋‹ˆ๋‹ค

์ด์ „ ๊ธ€ ๋ณด๊ธฐ(FastAPI ๋ผ์šฐํŒ… ์™„์ „ ์ •๋ณต)

โ€“ ๋ฐ์ดํ„ฐ๋Š” ์˜ค๊ณ , ์‘๋‹ต์€ ๊ฐ„๋‹ค: Pydantic, Request Body, Response ๋ชจ๋ธ ์™„์ „์ •๋ณต

โ€œAPI์˜ ์ง„์งœ ํž˜์€ ๋ฐ์ดํ„ฐ์—์„œ ๋‚˜์˜จ๋‹ค.โ€
ํด๋ผ์ด์–ธํŠธ์—์„œ ์„œ๋ฒ„๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๊ณ , ์„œ๋ฒ„๋Š” ๊ทธ์— ๋งž์ถฐ ์‘๋‹ต์„ ๋Œ๋ ค์ค€๋‹ค. ์ด๊ฒƒ์ด API์˜ ๊ธฐ๋ณธ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด๊ณ , FastAPI๋Š” ์ด๊ฑธ ๊ฐ€์žฅ ์•ˆ์ „ํ•˜๊ณ , ๊ฐ€์žฅ ๋น ๋ฅด๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ๋‹ค.

์ด๋ฒˆ ์‹œ๊ฐ„์—๋Š” FastAPI์˜ ์„ธ ๊ฐ€์ง€ ํ•ต์‹ฌ ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด ๋ฐฐ์›Œ๋ณธ๋‹ค:

  • Pydantic์„ ํ™œ์šฉํ•œ ๋ฐ์ดํ„ฐ ๊ฒ€์ฆ
  • Request Body๋ฅผ ํ†ตํ•ด ํด๋ผ์ด์–ธํŠธ๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ ๋ฐ›๊ธฐ
  • ์‘๋‹ต์„ ๋ช…ํ™•ํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” Response ๋ชจ๋ธ ์ •์˜

โœ… Pydantic์„ ํ™œ์šฉํ•œ ๋ฐ์ดํ„ฐ ๊ฒ€์ฆ

FastAPI๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ Pydantic์ด๋ผ๋Š” ๋ฐ์ดํ„ฐ ๊ฒ€์ฆ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ†ตํ•ด ์ž…๋ ฅ ๋ฐ์ดํ„ฐ์˜ ์œ ํšจ์„ฑ์„ ์ž๋™์œผ๋กœ ๊ฒ€์‚ฌํ•˜๊ณ , ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์€ ๋ฐ์ดํ„ฐ๋Š” 422 ์˜ค๋ฅ˜์™€ ํ•จ๊ป˜ ์นœ์ ˆํ•œ ๋ฉ”์‹œ์ง€๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

1. ๊ธฐ๋ณธ ์‚ฌ์šฉ ์˜ˆ

from pydantic import BaseModel

class Item(BaseModel):
    name: str
    price: float
    in_stock: bool
  • Item์ด๋ผ๋Š” ํด๋ž˜์Šค๋ฅผ ์ •์˜ํ–ˆ์ง€๋งŒ, ๋‹จ์ˆœํ•œ ํด๋ž˜์Šค๊ฐ€ ์•„๋‹ˆ๋‹ค.
  • ์ด๊ฑด ๋ฐ์ดํ„ฐ ๋ชจ๋ธ์ด์ž ๋™์‹œ์— ์ž…๋ ฅ ๊ฒ€์ฆ ๋„๊ตฌ๋‹ค.
  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ณด๋‚ธ JSON ๋ฐ์ดํ„ฐ๊ฐ€ ์ด ๋ชจ๋ธ๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š์œผ๋ฉด ์ž๋™์œผ๋กœ ๊ฑฐ๋ถ€๋œ๋‹ค.

2. ์ž๋™ ํƒ€์ž… ๊ฒ€์‚ฌ

  • name์—๋Š” ๋ฌธ์ž์—ด๋งŒ ๋“ค์–ด์™€์•ผ ํ•œ๋‹ค.
  • price์—๋Š” ์ˆซ์ž(float)๊ฐ€ ์™€์•ผ ํ•œ๋‹ค.
  • in_stock์—๋Š” Boolean ๊ฐ’๋งŒ ํ—ˆ์šฉ๋œ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ํด๋ผ์ด์–ธํŠธ๊ฐ€ "price": "cheap"๋ผ๊ณ  ๋ณด๋ƒˆ๋‹ค๋ฉด? โ†’ FastAPI๋Š” ๋ฐ”๋กœ ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.


๐Ÿ“ฅ Request Body ์ฒ˜๋ฆฌํ•˜๊ธฐ

์ด์ œ ๋ณธ๊ฒฉ์ ์œผ๋กœ POST ์š”์ฒญ์„ ํ†ตํ•ด ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ณด๋‚ธ JSON ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›๋Š” ๋ฐฉ๋ฒ•์„ ์‚ดํŽด๋ณด์ž.

1. POST ์š”์ฒญ ์˜ˆ์‹œ

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

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

@app.post("/items/")
def create_item(item: Item):
    return {"received_item": item}

2. ๋™์ž‘ ์›๋ฆฌ

  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ JSON ํ˜•์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๋ฉด FastAPI๋Š” Item ๋ชจ๋ธ์„ ๊ธฐ์ค€์œผ๋กœ ์œ ํšจ์„ฑ์„ ๊ฒ€์‚ฌํ•œ๋‹ค.
  • ์œ ํšจํ•œ ๊ฒฝ์šฐ item ์ธ์ž๋กœ ์ž๋™ ํŒŒ์‹ฑ๋˜์–ด ํ•จ์ˆ˜์— ์ „๋‹ฌ๋œ๋‹ค.
  • ์‘๋‹ต์€ ๋™์ผํ•œ ๊ตฌ์กฐ๋กœ JSON์œผ๋กœ ๋ฐ˜ํ™˜๋œ๋‹ค.

3. ํ…Œ์ŠคํŠธ ๋ฐฉ๋ฒ•

1. ์„œ๋ฒ„ ์‹คํ–‰:

uvicorn main:app --reload

2. Swagger ์ ‘์†: http://127.0.0.1:8000/docs

3. /items/ POST ์š”์ฒญ ์‹คํ–‰
JSON ์ž…๋ ฅ ์˜ˆ์‹œ:

{ "name": "Monitor", "price": 219.99, "description": "24-inch Full HD monitor" }

4. ์‘๋‹ต ๊ฒฐ๊ณผ:

{ "received_item": { "name": "Monitor", "price": 219.99, "description": "24-inch Full HD monitor" } }

4. ํ•„๋“œ ๊ธฐ๋ณธ๊ฐ’ ๋ฐ ์„ ํƒ๊ฐ’

  • description: str | None = None ์€ ์„ ํƒ ํ•ญ๋ชฉ์ž„
  • ์ž…๋ ฅ์—์„œ ๋น ์ ธ๋„ ์˜ค๋ฅ˜ ๋‚˜์ง€ ์•Š์Œ
  • ํƒ€์ž… ํžŒํŠธ๋ฅผ ์ •ํ™•ํžˆ ์จ์ฃผ๋ฉด ์ž๋™์œผ๋กœ ๋ฌธ์„œํ™”๋จ

๐Ÿ“ค Response ๋ชจ๋ธ ์ •์˜

API ์‘๋‹ต์„ ๊ฐœ๋ฐœ์ž ๋งˆ์Œ๋Œ€๋กœ ๊ตฌ์„ฑํ•˜๋ฉด ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์–ด๋ ต๊ณ , ๋ฌธ์„œํ™”๋„ ์–ด๋ ค์›Œ์ง„๋‹ค. ๊ทธ๋ž˜์„œ FastAPI๋Š” ์‘๋‹ต ํ˜•ํƒœ๋„ Pydantic ๋ชจ๋ธ๋กœ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•œ๋‹ค.

1. ์‘๋‹ต ๋ชจ๋ธ ์ง€์ • ์˜ˆ

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

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

class ItemResponse(BaseModel):
    name: str
    price: float

@app.post("/items/", response_model=ItemResponse)
def create_item(item: Item):
    return item

2. ์‘๋‹ต ๋ชจ๋ธ์ด ํ•˜๋Š” ์ผ

  • ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ๋Š” name๊ณผ price๋งŒ ๋ฐ˜ํ™˜๋˜๊ณ , description์€ ์ œ์™ธ๋จ
  • ๋‚ด๋ถ€ ๋กœ์ง์—์„œ๋Š” ์—ฌ์ „ํžˆ ์ „์ฒด ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ

์ฆ‰, ๋‚ด๋ถ€์—์„œ๋Š” ํ•„์š”ํ•œ ํ•„๋“œ ๋ชจ๋‘ ์ฒ˜๋ฆฌํ•˜๋˜, ํด๋ผ์ด์–ธํŠธ์—๋Š” ํ•„์š”ํ•œ ์ •๋ณด๋งŒ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

3. ๋ณด์•ˆ, UX ์ธก๋ฉด์—์„œ๋„ ์œ ๋ฆฌ

  • ๋ฏผ๊ฐ ์ •๋ณด(ex. ๋น„๋ฐ€๋ฒˆํ˜ธ)๋Š” ์‘๋‹ต์—์„œ ์ž๋™์œผ๋กœ ์ œ์™ธ ๊ฐ€๋Šฅ
  • ํ”„๋ก ํŠธ์—”๋“œ ์ž…์žฅ์—์„œ ํ•„์š”ํ•œ ์ •๋ณด๋งŒ ๋ฐ›์•„ UX ๊ฐœ์„  ๊ฐ€๋Šฅ

๐Ÿ’ก ๋ณด๋„ˆ์Šค: ์‘๋‹ต ์ƒํƒœ ์ฝ”๋“œ ์ง€์ •ํ•˜๊ธฐ

FastAPI๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ 200 ๋˜๋Š” 201 ๋“ฑ์˜ ์ƒํƒœ ์ฝ”๋“œ๋ฅผ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•˜์ง€๋งŒ, ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

from fastapi import status

@app.post("/items/", response_model=ItemResponse, status_code=status.HTTP_201_CREATED)
def create_item(item: Item):
    return item
  • status.HTTP_201_CREATED โ†’ 201 Created ์‘๋‹ต
  • ์ƒํƒœ ์ฝ”๋“œ๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ์ง€์ •ํ•ด์คŒ์œผ๋กœ์จ API ์˜๋„๋ฅผ ๋” ์ž˜ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿงพ ์ •๋ฆฌ: ๋ฐ์ดํ„ฐ ํ๋ฆ„์„ ์ œ์–ดํ•˜๋Š” ๊ฐ€์žฅ ํ™•์‹คํ•œ ๋ฐฉ๋ฒ•

์ง€๊ธˆ๊นŒ์ง€ FastAPI์—์„œ ๋ฐ์ดํ„ฐ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋“ค์–ด์˜ค๊ณ  ๋‚˜๊ฐ€๋Š”์ง€๋ฅผ ์‚ดํŽด๋ดค๋‹ค.

๊ฐœ๋…๊ธฐ๋Šฅ์„ค๋ช…
Pydantic์ž…๋ ฅ ๊ฒ€์ฆJSON ๋ฐ์ดํ„ฐ๋ฅผ Python ๊ฐ์ฒด๋กœ ์ž๋™ ๋ณ€ํ™˜ & ๊ฒ€์ฆ
Request Body์ž…๋ ฅ ์ฒ˜๋ฆฌPOST/PUT ๋“ฑ์˜ ์š”์ฒญ ๋ณธ๋ฌธ์„ ์ฒ˜๋ฆฌ
Response Model์ถœ๋ ฅ ์ œ์–ด์‘๋‹ต ๊ตฌ์กฐ๋ฅผ ์ •์˜ํ•ด ์ผ๊ด€์„ฑ ํ™•๋ณด
์ƒํƒœ ์ฝ”๋“œ์‘๋‹ต ์˜๋ฏธHTTP ํ‘œ์ค€์— ๋งž๋Š” ์˜๋ฏธ ์ „๋‹ฌ

FastAPI ๊ณต์‹ ๋ฌธ์„œ : https://fastapi.tiangolo.com/ko/

fastapi-logo,fastapi-๊ฐœ๋ฐœ-ํ™˜๊ฒฝ-์„ค์ •, fastapi-์•ฑ-๋งŒ๋“ค๊ธฐ, fastapi-๋ผ์šฐํŒ…, fastapi-request-response