FastAPI에서는 Path, Query, 본문 매개변수를 혼합하여 사용할 수 있습니다. FastAPI는 이러한 매개변수들의 동작 방식을 알고 자동으로 처리해줍니다. 이 기능을 활용하면 복잡한 API를 더욱 유연하게 설계할 수 있습니다.
경로 매개변수, 쿼리 매개변수, 본문 매개변수를 혼합하여 사용할 수 있으며, 기본값을 None으로 설정하여 본문 매개변수를 선택사항으로 만들 수도 있습니다.
from typing import Union
from fastapi import FastAPI, Path
from pydantic import BaseModel
app = FastAPI()
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: int = Path(title="The ID of the item to get", ge=0, le=1000),
q: Union[str, None] = None,
item: Union[Item, None] = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
if item:
results.update({"item": item})
return results
본문 매개변수는 한 개 이상을 선언할 수 있습니다. 예를 들어, item과 user라는 두 개의 본문 매개변수를 선언하여 사용할 수 있습니다.
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
class User(BaseModel):
username: str
full_name: Union[str, None] = None
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item, user: User):
results = {"item_id": item_id, "item": item, "user": user}
return results
이 경우, FastAPI는 두 개 이상의 본문 매개변수가 있는 것을 인식하며, 다음과 같은 JSON 본문을 예상합니다:
{
"item": {
"name": "Foo",
"description": "The pretender",
"price": 42.0,
"tax": 3.2
},
"user": {
"username": "dave",
"full_name": "Dave Grohl"
}
}
단일 값을 본문에서 받으려면 Body를 사용할 수 있습니다. 이는 쿼리나 경로 매개변수로 처리되는 대신 본문 내에서 처리되도록 강제할 수 있습니다.
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
class User(BaseModel):
username: str
full_name: Union[str, None] = None
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item, user: User, importance: int = Body()):
results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
return results
{
"item": {
"name": "Foo",
"description": "The pretender",
"price": 42.0,
"tax": 3.2
},
"user": {
"username": "dave",
"full_name": "Dave Grohl"
},
"importance": 5
}
쿼리 매개변수와 본문 매개변수를 혼합하여 사용할 수 있습니다.
from fastapi import Body, FastAPI
from pydantic import BaseModel
from typing import Union
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
class User(BaseModel):
username: str
full_name: Union[str, None] = None
@app.put("/items/{item_id}")
async def update_item(
*,
item_id: int,
item: Item,
user: User,
importance: int = Body(gt=0),
q: Union[str, None] = None,
):
results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
if q:
results.update({"q": q})
return results
gt=0으로 숫자가 0보다 커야 합니다.본문 내에 단일 매개변수만 있을 때도 Body의 embed=True를 사용해 JSON의 특정 키로 값을 삽입할 수 있습니다.
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
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: int, item: Item = Body(embed=True)):
results = {"item_id": item_id, "item": item}
return results
item이라는 키 아래 값을 받습니다.{
"item": {
"name": "Foo",
"description": "The pretender",
"price": 42.0,
"tax": 3.2
}
}
알겠습니다! 이제 벨로그 규칙을 적용하여 포맷을 수정하겠습니다.
Query, Path와 Body를 사용해 경로 작동 함수 매개변수 내에서 추가적인 검증이나 메타데이터를 선언한 것처럼 Pydantic의 Field를 사용하여 모델 내에서 검증과 메타데이터를 선언할 수 있습니다.
먼저 이를 임포트해야 합니다:
from typing import Annotated
from fastapi import Body, FastAPI
from pydantic import BaseModel, Field
그 다음 모델 어트리뷰트와 함께 Field를 사용할 수 있습니다:
class Item(BaseModel):
name: str
description: 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: float | None = None
Field는 Query, Path, Body와 같은 방식으로 동작하며, 모두 같은 매개변수들을 가집니다.
실제로 Query, Path 등은 공통 클래스인 Param 클래스의 서브클래스 객체를 만드는데, 그 자체로 Pydantic의 FieldInfo 클래스의 서브클래스입니다.
Field, Query, Body 등에 별도 정보를 선언하여, JSON 스키마에 추가적인 메타데이터를 전달할 수 있습니다.
별도 키가 전달된 Field는 여러분의 애플리케이션의 OpenAPI 스키마에 나타날 것입니다. 이런 키가 OpenAPI 명세서에 포함되지 못할 수 있으며, 여러분이 생성한 스키마와 호환되지 않을 수 있습니다.
Field는 Pydantic 모델의 어트리뷰트를 위한 추가적인 검증과 메타데이터를 선언할 수 있게 해줍니다. OpenAPI 스키마 문서화에도 도움이 됩니다.
와, 정말 감사합니다! 💯 제가 더 세세하게 다듬어서 정리해드릴게요. 이 작업은 구조화된 정보가 많고 세부 사항이 상당히 많기 때문에, 순차적으로 최종적인 완성도를 높여가며 최대한 자세하고 깔끔하게 정리하겠습니다.
FastAPI는 Pydantic 덕분에 깊이 중첩된 모델을 간단하게 정의하고 사용할 수 있습니다. 이는 복잡한 JSON 구조를 처리할 때 매우 유용합니다.
list 필드는 Pydantic 모델에서 리스트형 데이터를 처리할 수 있습니다. 예를 들어, 아이템을 설명하는 태그 리스트를 다룰 때 다음과 같은 코드를 사용할 수 있습니다.
from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
tags: list = []
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
이 코드에서 tags는 항목 리스트로 정의됩니다. 각 항목의 타입을 구체적으로 정의하지 않아도 사용할 수 있지만, 더 명확하게 타입을 정의하는 것이 좋습니다.
리스트 안에 포함된 항목들의 타입을 명시적으로 정의할 수 있습니다. 예를 들어 List[str]는 문자열로 이루어진 리스트를 뜻합니다.
리스트에 들어가는 항목들의 타입을 명확히 정의하기 위해서는 파이썬의 typing 모듈에서 List를 임포트해야 합니다.
from typing import List, Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
tags: List[str] = []
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
이 코드는 tags 필드를 문자열 리스트로 정의합니다. 이 방식으로 내부 데이터의 타입을 명확하게 관리할 수 있습니다.
리스트와 다르게 중복된 항목을 허용하지 않는 집합(set)도 사용할 수 있습니다. 집합은 고유한 항목들만 포함하게 됩니다.
from typing import Set, Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
tags: Set[str] = set()
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
위 코드에서 tags는 중복되지 않는 문자열의 집합을 의미합니다. 만약 중복된 태그가 입력되더라도 집합으로 변환되면서 중복을 제거합니다.
Pydantic을 사용하면 모델 내에서 또 다른 모델을 중첩시켜 사용할 수 있습니다. 이 방식은 복잡한 JSON 구조를 처리하는 데 매우 유용합니다.
예를 들어 Image라는 모델을 정의한 뒤, 이를 Item 모델 내에서 사용할 수 있습니다.
from typing import Set, Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Image(BaseModel):
url: str
name: str
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
tags: Set[str] = set()
image: Union[Image, None] = None
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
Item 모델에 image라는 필드가 추가되고, 이는 Image 모델을 참조합니다. 이 방식으로 Item 모델 안에 또 다른 모델을 중첩할 수 있습니다.
모델 내부에 리스트로 서브모델을 정의할 수 있습니다. 이를 통해 여러 개의 서브모델을 처리할 수 있습니다.
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
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
위 코드에서는 images 필드가 Image 모델의 리스트로 정의되었습니다. 이렇게 하면 여러 개의 이미지 데이터를 다룰 수 있습니다.
FastAPI는 깊이 중첩된 모델도 쉽게 처리할 수 있습니다. 예를 들어 Offer라는 모델이 Item의 리스트를 가지고, 각 Item은 또 Image 리스트를 가질 수 있습니다.
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
이 예제에서는 Offer라는 모델이 Item들의 리스트를 포함하고, 각 Item은 Image 리스트를 포함하는 구조입니다.
JSON 본문이 리스트일 때도 모델을 정의할 수 있습니다. 예를 들어 이미지들의 리스트를 처리하는 API를 작성할 수 있습니다.
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
이 함수는 여러 개의 Image 객체를 리스트로 받아들입니다.
복잡한 키-값 구조의 dict를 받을 수도 있습니다. 예를 들어, 정수 키와 실수 값을 가지는 딕셔너리를 받는 예제입니다.
from typing import Dict
from fastapi import FastAPI
app = FastAPI()
@app.post("/index-weights/")
async def create_index_weights(weights: Dict[int, float]):
return weights
JSON은 문자열 키만을 지원하지만, FastAPI는 이를 자동으로 변환하여 처리해줍니다.
FastAPI는 복잡한 데이터 구조를 처리할 때도 매우 간결하고 직관적인 방식으로 사용할 수 있습니다. 이를 통해 다음과 같은 장점들을 얻을 수 있습니다:
된 OpenAPI 문서)