darly213 2023. 3. 30. 11:44
728x90

โ€ป FastAPI Tutorial์„ ๊ณต๋ถ€ํ•˜๋ฉฐ ์ดํ•ดํ•œ๋Œ€๋กœ ์ž‘์„ฑํ•œ ๋‚ด์šฉ์œผ๋กœ, ์‹ค์ œ ๋‚ด์šฉ๊ณผ ๋‹ค๋ฅด๊ฑฐ๋‚˜ ํ‹€๋ฆฐ ๋ถ€๋ถ„์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋Œ“๊ธ€๋กœ ์•Œ๋ ค์ฃผ์‹œ๋ฉด ์ฆ‰์‹œ ๋ฐ˜์˜ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

https://fastapi.tiangolo.com/ko/tutorial/

[์ž์Šต์„œ - ์‚ฌ์šฉ์ž ์•ˆ๋‚ด์„œ - ๋„์ž…๋ถ€ - FastAPI

์ž์Šต์„œ - ์‚ฌ์šฉ์ž ์•ˆ๋‚ด์„œ - ๋„์ž…๋ถ€ ์ด ์ž์Šต์„œ๋Š” FastAPI์˜ ๋Œ€๋ถ€๋ถ„์˜ ๊ธฐ๋Šฅ์„ ๋‹จ๊ณ„๋ณ„๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ๊ฐ ์„น์…˜์€ ์ด์ „ ์„น์…˜์„ ๊ธฐ๋ฐ˜ํ•ด์„œ ์ ์ง„์ ์œผ๋กœ ๋งŒ๋“ค์–ด ์กŒ์ง€๋งŒ, ์ฃผ์ œ์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ

fastapi.tiangolo.com](https://fastapi.tiangolo.com/ko/tutorial/)


1. Body - ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜

class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None

@app.put("/items/{item_id}")
async def update_item(
    item_id: Annotated[int, Path(title="the ID of the item to get", ge=0, le=1000)],
    q: Union[str, None] = None,
    item: Union[Item, None] = None
):
    result = {"item_id": item_id}
    if q:
        result.update({"q": q})
    if item:
        result.update({"item": item})

    return result

Body - ๋‹จ์ผ ๋ณ€์ˆ˜

@app.put("/body/{item_id}")
async def update_body(
    item_id: int, item: Item, user: User, importance: Annotated[int, Body()]
):
    results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
    return results
  • importance: Annotated[int, Body()] ⇒ ์ด๋Ÿฌ๋ฉด ๋ฐ์ดํ„ฐ ๋ชฉ๋ก-๊ทธ๋Ÿฌ๋‹ˆ๊นŒ response body์— ํฌํ•จ๋จ
  • ์ด๋Ÿฌ์ง€ ์•Š์œผ๋ฉด Query ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ํŒ๋‹จ๋˜๊ณ  ๋ฐ์ดํ„ฐ ๋ฐ”๋””๋กœ ๋“ค์–ด๊ฐ€์ง€ ์•Š์Œ. ์œ„๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์•„๋ž˜์ฒ˜๋Ÿผ ๋‚˜์˜จ๋‹ค.
    • query ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” ์ฃผ์†Œ์ฐฝ์— ํ‘œ์‹œ๋˜๊ณ , body์— ํฌํ•จ๋˜๋Š” ์นœ๊ตฌ๋“ค์€ ํ‘œ์‹œ๋˜์ง€ ์•Š๋Š”๋‹ค.
    • ๋ณด์•ˆ์ƒ์˜ ์˜๋ฏธ๊ฐ€ ํฐ ๊ฒƒ ๊ฐ™๋‹ค.
    • { "item_id": 3, "item": { "name": "hell", "description": "biohazard", "price": 0, "tax": 0 }, "user": { "username": "mia", "full_name": "edan" }, "importance": 10 }

๋‹ค์ค‘ ๋ณ€์ˆ˜

@app.put("/body/{item_id}")
async def update_body(
    item_id: int, item: Item, user: User, importance: Annotated[int, Body()], q: Union[str, None] = None
):
    results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
    return results
  • ์œ„์™€ ๊ฐ™์ด ์ผ๋ฐ˜ ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜์™€ ํ•จ๊ป˜ ์“ฐ๋Š” ๊ฒƒ๋„ ๋‹น์—ฐํžˆ ๊ฐ€๋Šฅํ•จ

๋”ฑ ํ•˜๋‚˜๋งŒ body์— ํฌํ•จ์‹œํ‚ค๊ณ ์ž ํ•  ๋•Œ

@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]):
    results = {"item_id": item_id, "item": item}
    return results
  • Body(embed=True) ๋ฅผ ๋ถ™์ด๋ฉด ์™ผ์ชฝ์ด ์˜ค๋ฅธ์ชฝ์ฒ˜๋Ÿผ ๋ณ€ํ•จ
{
    "item": {
        "name": "Foo",
        "description": "The pretender",
        "price": 42.0,
        "tax": 3.2
    }
}

2. Body - Field

⇒ pydantic model ์•ˆ์—์„œ ์†์„ฑ์„ ์ถ”๊ฐ€ํ•  ๋•Œ = field

from typing import Union

from fastapi import Body, FastAPI
from pydantic import BaseModel, Field
from typing_extensions import Annotated

app = FastAPI()

class Item(BaseModel):
    name: str
    description: Union[str, None] = Field(
        default=None, title="The description of the item", max_length=300
    )
    price: float = Field(gt=0, description="The price must be greater than zero")
    tax: Union[float, None] = None

@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]):
    results = {"item_id": item_id, "item": item}
    return results

3. Body - Nested models

from typing import List, Set, Union

from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl

app = FastAPI()

class Image(BaseModel):
    url: HttpUrl
    name: str

class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None
    tags: Set[str] = set()
    images: Union[List[Image], None] = None

class Offer(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    items: List[Item]

@app.post("/offers/")
async def create_offer(offer: Offer):
    return offer
  • ์—ฐ์‡„์ ์œผ๋กœ ์ •์˜ํ•œ ํด๋ž˜์Šค๋ฅผ ์ž๋ฃŒํ˜•๋งˆ๋ƒฅ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์ œ
  • ๋‹จ์ˆœ ๋ฆฌ์ŠคํŠธ๋กœ ๊ตฌ์„ฑ๋œ body๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
from typing import List

from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl

app = FastAPI()


class Image(BaseModel):
    url: HttpUrl
    name: str


@app.post("/images/multiple/")
async def create_multiple_images(images: List[Image]):
    return images
  • dictionary์˜ ๊ฒฝ์šฐ key์™€ value์˜ ์ž๋ฃŒํ˜•์„ ๋”ฐ๋กœ.
@app.post("/index-weights/")
async def create_index_weights(weights: Dict[int, float]):
    return weights

4.Request ์˜ˆ์‹œ ๋ฐ์ดํ„ฐ ์„ ์–ธ

⇒ Pydantic model์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ํด๋ž˜์Šค์—์„œ๋Š” config๋ผ๋Š” ์„œ๋ธŒ ํด๋ž˜์Šค์™€ schema_extra๋ผ๋Š” ๊ฑฐ ์“ฐ๋ฉด ๋œ๋‹ค.

class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None

    class Config:
        schema_extra = {
            "example": {
                "name": "Foo",
                "description": "A very nice Item",
                "price": 35.4,
                "tax": 3.2,
            }
        }

@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results
# ๊ธฐ๋ณธ ์˜ˆ์‹œ๋ฐ์ดํ„ฐ๊ฐ€ request body์— ๋ฏธ๋ฆฌ ์žˆ์Œ. JSON
{
  "name": "Foo",
  "description": "A very nice Item",
  "price": 35.4,
  "tax": 3.2
}
  • Field ์—๋„ ๋”ฐ๋กœ example์„ ๋„ฃ์–ด์ฃผ๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ๋‹ค.

Body๋กœ Annotatedํ•  ๋•Œ ์˜ˆ์‹œ ๋„ฃ๊ธฐ

@app.put("/items/{item_id}")
async def update_item(
    item_id: int,
    item: Annotated[
        Item, 
        Body(
            example={
                "name": "Foo",
                "description": "A very nice item",
                "price": 24.3,
                "tax": 3.3
            }
        )
    ]
):
    results = {"item_id": item_id, "item": item}
    return results    
  • ์—ฌ๋Ÿฌ ๊ฐœ์˜ example ๋„ฃ๊ธฐ?
@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Annotated[
        Item,
        Body(
            examples={
                "normal": {
                    "summary": "A normal example",
                    "description": "A **normal** item works correctly.",
                    "value": {
                        "name": "Foo",
                        "description": "A very nice Item",
                        "price": 35.4,
                        "tax": 3.2,
                    },
                },
                "converted": {
                    "summary": "An example with converted data",
                    "description": "FastAPI can convert price `strings` to actual `numbers` automatically",
                    "value": {
                        "name": "Bar",
                        "price": "35.4", # string to number automatically
                    },
                },
                "invalid": {
                    "summary": "Invalid data is rejected with an error",
                    "value": {
                        "name": "Baz",
                        "price": "thirty five point four", # float์ธ๋ฐ string
                    },
                },
            },
        ),
    ],
):
    results = {"item_id": item_id, "item": item}
    return results


5. Cookie ๋งค๊ฐœ๋ณ€์ˆ˜

from typing import Union

from fastapi import Cookie, FastAPI
from typing_extensions import Annotated

app = FastAPI()

@app.get("/items/")
async def read_items(ads_id: Annotated[Union[str, None], Cookie()] = None):
    return {"ads_id": ads_id}

6. Header ๋งค๊ฐœ๋ณ€์ˆ˜

  • ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๋‹ด๊ณ  ์žˆ์Œ.
from typing import Union

from fastapi import FastAPI, Header

app = FastAPI()

@app.get("/items/")
async def read_items(user_agent: Union[str, None] = Header(default=None)):
    return {"User-Agent": user_agent}

→ ๊ธฐ๋ณธ์ ์œผ๋กœ path, query, cookie์™€ ๊ฐ™์€ ๊ธฐ๋Šฅ

  • ์ถ”๊ฐ€ ๊ธฐ๋Šฅ : ์–ธ๋”๋ฐ”(_)๋ฅผ ํ•˜์ดํ”ˆ(-)์œผ๋กœ ์ž๋™ ๋ณ€ํ™˜ HTTP ํ‘œ์ค€ ํ—ค๋” ๊ทœ๊ฒฉ
  • ์ค‘๋ณต์ ์œผ๋กœ header๋ฅผ ์ „์†กํ•˜๋Š” ๊ฒฝ์šฐ ํŒŒ์ด์ฌ ๋ฆฌ์ŠคํŠธ๋กœ ์ €์žฅ

7. ์‘๋‹ต ๋ชจ๋ธ - ๋ฐ˜ํ™˜ํ˜•

1. ์ผ๋ฐ˜ ํŒŒ์ด์ฌ docstring ๋ฌธ๋ฒ•๋Œ€๋กœ ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜ํ˜•์„ ํ‘œ๊ธฐํ•˜๊ธฐ

@app.post("/items/")
async def create_item(item: Item) -> Item: # return type = Item object
    return item

@app.get("/items/")
async def read_items() -> List[Item]: # return type = list of Item object
    return [
        Item(name="Portal Gun", price=42.0),
        Item(name="Plumbus", price=32.0),
    ]

2. response_model parameter ์‚ฌ์šฉํ•˜๊ธฐ

์œ ์‚ฌ์‹œ ํŒŒ์ด์ฌ ์˜ค๋ฅ˜๋ฅผ ๋ง‰๊ธฐ ์œ„ํ•ด์„œ ์“ธ ์ˆ˜ ์žˆ์Œ. FastAPI์—์„œ ์ถœ๋ ฅ ๋ฐ์ดํ„ฐ๋ฅผ response model์˜ ์ž๋ฃŒํ˜•์œผ๋กœ ๋ณ€ํ™˜ ๋ฐ ํ•„ํ„ฐ๋ง

@app.post("/items/", response_model=Item)
async def create_item(item: Item) -> Any:
    return item

@app.get("/items/", response_model=List[Item])
async def read_items() -> Any:
    return [
        {"name": "Portal Gun", "price": 42.0},
        {"name": "Plumbus", "price": 32.0},
    ]
  • ๋”ฐ๋ผ์„œ ์ž…๋ ฅ๋ฐ›์€ ๋ฐ์ดํ„ฐ ์ค‘ ์ผ๋ถ€๋ฅผ ํ•„ํ„ฐ๋งํ•ด์„œ ์ถœ๋ ฅ์œผ๋กœ ๋Œ๋ฆฌ๊ณ  ์‹ถ์œผ๋ฉด ๊ทธ๊ฒƒ๋„ ๊ฐ€๋Šฅ!
class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Union[str, None] = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: Union[str, None] = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
    return user
  • ์ด ๊ฒฝ์šฐ ์ž…๋ ฅ ๋ฐ์ดํ„ฐ์—์„œ password๋ฅผ ํ•„ํ„ฐ๋งํ•œ UserOut์œผ๋กœ ์ž๋™ ๋ณ€ํ™˜
  • python ์ผ๋ฐ˜ ํ•จ์ˆ˜ ๋ฐ˜ํ™˜์—๋‹ค๊ฐ€ ์“ฐ๋ฉด ๋‘˜์ด ๋‹ฌ๋ผ์„œ ์•ˆ๋œ๋‹ค๊ณ  ์˜ค๋ฅ˜๋‚จ.
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()

class BaseUser(BaseModel):
    username: str
    email: EmailStr
    full_name: Union[str, None] = None


class UserIn(BaseUser): # BaseUser ์ƒ์†!
    password: str
    # username: str
    # email: EmailStr
    # full_name: Union[str, None] = None

@app.post("/user/")
async def create_user(user: UserIn) -> BaseUser:
    return user

⇒ ์ด ๊ฒฝ์šฐ BaseUser์— UserIn์ด ๊ฐ€์ง„ ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•˜๋‚˜๋„ ์—†๋Š”๋ฐ?

  • ์ƒ์† ๋ฐ›์•˜์œผ๋‹ˆ๊นŒ UserIn์— BaseUser๊ฐ€ ๊ฐ€์ง„ ๊ฒƒ์ด ์ƒ์†๋˜์–ด์žˆ์Œ. ๋”ฐ๋ผ์„œ ์ƒ์†๋ฐ›์€ ๊ฒƒ๋“ค์€ ํ•„ํ„ฐ์— ์•ˆ ๊ฑธ๋ฆฌ๊ณ  ์—†๋Š” password๋งŒ ๊ฑธ๋ฆผ.
  • ๊ฒฐ๊ณผ
# request body
{
  "username": "dain",
  "email": "dmelli0505@gmail.com",
  "full_name": "dain kang",
  "password": "123456789"
}

# response body
{
  "username": "dain",
  "email": "dmelli0505@gmail.com",
  "full_name": "dain kang"
}

3. ์‘๋‹ต ์ง์ ‘ ๋ฐ˜ํ™˜

from fastapi.responses import JSONResponse, RedirectResponse
from fastapi import FastAPI, Response

app = FastAPI()

@app.get("/portal")
async def get_potal(teleport: bool = False) -> Response:
    if teleport:
        return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
    return JSONResponse(content={"message": "Here's your interdimenseional portal."})

๋” ํ•˜์œ„ response๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ๋„ ok.

  • ๊ทธ๋Ÿฌ๋‚˜ ๋ฐ˜ํ™˜ํ˜•์ด A or B๋Š” ์•ˆ๋จ.
@app.get("/portal")
async def get_portal(teleport: bool = False) -> Union[Response, dict]:
    if teleport:
        return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
    return {"message": "Here's your interdimensional portal."}
  • ์ด ๊ฒฝ์šฐ Response or Dictionary ๋ฐ˜ํ™˜? ๋ช…์‹œ์ ์ด์ง€ ์•Š์œผ๋ฏ€๋กœ ๋ถˆ๊ฐ€๋Šฅ
  • @app.get("/portal/", response_model=None) ํ•˜๋ฉด ๋น„ํ™œ์„ฑํ™” 

4. ์‘๋‹ต ๋ชจ๋ธ ๋งค๊ฐœ๋ณ€์ˆ˜

⇒ ์‘๋‹ต๋ชจ๋ธ๋„ ๊ธฐ๋ณธ๊ฐ’์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Œ.

class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: float = 10.5
    tags: List[str] = []
@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
  • ์ด๋ ‡๊ฒŒ ์“ฐ๋ฉด ๊ธฐ๋ณธ๊ฐ’ ์žˆ๋Š” ๊ฒƒ๋“ค ๋นผ๊ณ  ๋‚˜๋จธ์ง€๋งŒ response๋กœ ๋“ค์–ด๊ฐ.
    • { name: "temp", price: 2134 }
  • ๊ทธ๋Ÿฌ๋‚˜ ๋ฏธ๋ฆฌ ๋ฐ์ดํ„ฐ์— ๊ธฐ๋ณธ๊ฐ’๊ณผ ๊ฐ™์€ ๊ฐ’์ด ๋“ค์–ด์žˆ๋Š” ๊ฒฝ์šฐ์—๋Š” ํ‰๋ฒ”ํ•˜๊ฒŒ ์ „๋ถ€ response๋กœ ๋“ค์–ด๊ฐ.
items = [
	{
		name: "temp",
		description: None,
		price: 2134,
		tax: 10.5,
		tags: []
	},
	...
]

# temp.com/items/0 -> response
	{
		name: "temp",
		description: None,
		price: 2134,
		tax: 10.5,
		tags: []
	}

 


8. ์ž…๋ ฅ / ์ถœ๋ ฅ / DB ๋ชจ๋ธ

  • ์ž…๋ ฅ ๋ชจ๋ธ = ๋น„๋ฐ€๋ฒˆํ˜ธ ํ•„์š”
  • ์ถœ๋ ฅ ๋ชจ๋ธ = ๋น„๋ฐ€๋ฒˆํ˜ธ ํฌํ•จํ•˜๋ฉด ์•ˆ๋จ
  • DB ๋ชจ๋ธ = ํ•ด์‹œ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Œ
class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Union[str, None] = None

class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: Union[str, None] = None

class UserInDB(BaseModel):
    username: str
    hashed_password: str
    email: EmailStr
    full_name: Union[str, None] = None

→ ์œ ์ € ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€๊ณตํ•˜๋Š” ๋ถ€๋ถ„

def fake_password_hasher(raw_password: str):
    return "supersecret" + raw_password

def fake_save_user(user_in: UserIn):
    hashed_password = fake_password_hasher(user_in.password)
    user_in_db = UserInDB(**user_in.dict(), hashed_password=hashed_password)
    print("User saved! ...really?")
    return user_in_db
  • return type UserInDB
  • **user_in.dict() ๋Š” Pydantic model์˜ method์ธ๋ฐ, model data์— ๋Œ€ํ•œ dictionary๋ฅผ ์ œ๊ณตํ•œ๋‹ค.
**user_in.dict() ⇒ {
  "username": "dump",
  "password": "1234",
  "email": "dump@example.com",
  "full_name": "dump dumpio"
}
  • ๊ทธ๋ฆฌ๊ณ  ๊ฒน์น˜๋Š” key์—๋งŒ unwrapping ํ•˜๋ฏ€๋กœ UserInDB ์—์„œ๋Š” username, email, full_name๋งŒ ๋‚จ๊ฒŒ ๋œ๋‹ค. ๊ฑฐ๊ธฐ์— hashed_password๋ฅผ ๋”ํ•ด์„œ ๊ตฌ์„ฑํ•œ ๊ฒƒ.
@app.post("/user/", response_model=UserOut)
async def create_user(user_in: UserIn):
    user_saved = fake_save_user(user_in=user_in)
    return user_saved
  • ๊ฒฐ๊ณผ
# Request body
{
  "username": "dump",
  "password": "1234",
  "email": "dump@example.com",
  "full_name": "dump dumpio"
}

# Response body
{
  "username": "dump",
  "email": "dump@example.com",
  "full_name": "dump dumpio"
}

์ด์ค‘ ์„ ์–ธ ์ง€์–‘ํ•˜๊ธฐ

class UserBase(BaseModel):
    username: str
    email: EmailStr
    full_name: Union[str, None] = None

class UserIn(UserBase):
    password: str

class UserOut(UserBase):
    pass

class UserInDB(UserBase):
    hashed_password: str

์ƒ์†๋ฐ›์•„์„œ ๊ธธ์ด ์ค„์ด๊ธฐ

๊ธฐํƒ€ response model

  • ๋ฆฌํ„ด ๋ชจ๋ธ์ด ๋‘˜ ์ค‘ ํ•˜๋‚˜์ผ ๋•Œ ⇒ Union
@app.get("/items/{item_id}", response_model=Union[PlaneItem, CarItem])  # Union์œผ๋กœ
async def read_item(item_id: str):
    return items[item_id]
  • ๋ฆฌํ„ด ๋ชจ๋ธ์„ List ๋กœ ์‚ฌ์šฉ๋„ ๊ฐ€๋Šฅ
@app.get("/items/", response_model=List[Item])
async def read_items():
    return items
  • field / attribute ์ด๋ฆ„์•Œ ์ž˜ ๋ชจ๋ฅผ ๋•Œ Dictionary ํ˜•ํƒœ๋กœ๋„ response๋ฅผ ๋ฐ˜ํ™˜ ๊ฐ€๋Šฅํ•˜๋‹ค.
from typing import Dict

from fastapi import FastAPI

app = FastAPI()


@app.get("/keyword-weights/", response_model=Dict[str, float])
async def read_keyword_weights():
    return {"foo": 2.3, "bar": 3.4}
  • Dict[str, float] ์ด๋ฏ€๋กœ key = string, value = float ํ˜•์ธ ๋”•์…”๋„ˆ๋ฆฌ๊ฐ€ return ๋  ์˜ˆ์ •์ž„์„ ๋ช…์‹œ

9. ์‘๋‹ต ์ƒํƒœ ์ฝ”๋“œ

  • @app.get()
  • @app.post()
  • @app.put()
  • @app.delete()

์™€ ๊ฐ™์€ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ–ˆ์„ ๋•Œ 404 error์™€ ๊ฐ™์ด ์‘๋‹ต ์ƒํƒœ ์ฝ”๋“œ๋ฅผ ๋ฐ›์•„๋ณผ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด๋ฅผ status_code ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

from fastapi import FastAPI

app = FastAPI()

@app.post('/items/', status_code=201)
async def create_item(name:str):
    return {"name": name}

HTTP ์ƒํƒœ์ฝ”๋“œ

  • 1xx : ์ •๋ณด. ์ง์ ‘์ ์œผ๋กœ ์‚ฌ์šฉ๋˜์ง€ ์•Š์œผ๋ฉฐ body๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์—†์Œ
  • 2xx : ์„ฑ๊ณต์ ์ธ ์‘๋‹ต.
    • 200 : ์ „์ฒด ์„ฑ๊ณต
    • 201 : ์ƒ์„ฑ๋จ - DB์— ์ƒˆ๋กœ์šด ๋ ˆ์ฝ”๋“œ ์ƒ์„ฑ ํ›„ ์‚ฌ์šฉ
    • 204 : ๋‚ด์šฉ ์—†์Œ - ํด๋ผ์ด์–ธํŠธ์— ๋ฐ˜ํ™˜ํ•  ๊ฒƒ ์—†์Œ. body๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์—†์Œ.
  • 3xx : ๋ฆฌ๋‹ค์ด๋ ‰์…˜์šฉ - body๊ฐ€ ์žˆ์„ ์ˆ˜๋„ ์žˆ๊ณ , ์—†์„ ์ˆ˜๋„ ์žˆ์Œ.
    • 304 : ์ˆ˜์ •๋˜์ง€ ์•Š์Œ - body ์—†์Œ
  • 4xx : ํด๋ผ์ด์–ธํŠธ ์˜ค๋ฅ˜
    • 404 : ์ฐพ์„ ์ˆ˜ ์—†์Œ
    • 400 : ์ผ๋ฐ˜ ํด๋ผ์ด์–ธํŠธ ์˜ค๋ฅ˜
  • 5xx : ์„œ๋ฒ„ ์˜ค๋ฅ˜

FastAPI์—์„œ ํŽธ์˜ ๋ณ€์ˆ˜ ์‚ฌ์šฉ

from fastapi import FastAPI, status

app = FastAPI()

@app.post("/items/", status_code=status.HTTP_201_CREATED)
async def create_item(name: str):
    return {"name": name}
728x90