요청 예시 데이터 선언하기
요청 예시 데이터 선언하기 (Declare Request Example Data)
API 문서에 요청 본문이 어떤 모양인지 예시로 보여주고 싶을 때가 있어요. FastAPI에서는 Pydantic 모델이나 Body()/Query() 같은 파라미터에 **examples**를 선언해서, 이 예시가 OpenAPI의 JSON Schema에 들어가도록 만들 수 있어요. 그러면 문서 UI(Swagger UI)에도 그 예시가 그대로 보여서, 사용자가 어떤 데이터를 보내야 하는지 한눈에 알게 돼요.
출처: 공식문서
Pydantic 모델에서 JSON Schema에 extra 데이터 넣기
Pydantic 모델 안에 model_config의 json_schema_extra로 예시를 담을 수 있어요. 이 방식은 모델 자체의 JSON Schema에 examples를 심는 거예요.
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
model_config = {
"json_schema_extra": {
"examples": [
{
"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
Field()의 examples로 필드별 예시 넣기
필드 단위로 예시를 지정하고 싶다면, Field()에 examples를 넘기면 돼요. 필드마다 어떤 값이 들어가면 좋을지 하나씩 보여줄 수 있어요.
from fastapi import FastAPI
from pydantic import BaseModel, Field
app = FastAPI()
class Item(BaseModel):
name: str = Field(examples=["Foo"])
description: str | None = Field(default=None, examples=["A very nice Item"])
price: float = Field(examples=[35.4])
tax: float | None = Field(default=None, examples=[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
examples를 JSON Schema - OpenAPI에서 선언하기
이번에는 Pydantic 모델이 아니라, FastAPI의 파라미터들에 직접 examples를 선언하는 방법이에요. 다음 중 아무 데나 쓸 수 있어요.
Path()Query()Header()Cookie()Body()Form()File()
예를 들어 Body()에 examples를 주면, 그 예시가 OpenAPI의 JSON Schema에 포함돼요.
from typing import Annotated
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
@app.put("/items/{item_id}")
async def update_item(
item_id: int,
item: Annotated[
Item,
Body(
examples=[
{
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
}
],
),
],
):
results = {"item_id": item_id, "item": item}
return results
참고
Annotated를 쓰고 싶지 않다면item: Item = Body(examples=[...])형태로도 같은 동작을 해요.
Body에 여러 examples 넣기
Body()의 examples는 리스트라서, 여러 개의 예시를 한 번에 담을 수도 있어요. 아래 코드는 세 가지 예시를 보여주는데, 특히 price를 보면 자료형이 제각각이에요. 하나는 숫자 35.4이고, 다음은 문자열 "35.4", 또 하나는 문자열 "thirty five point four"예요. FastAPI는 본문을 받을 때 이 값들 중 유효한 것만 통과시키겠죠.
from typing import Annotated
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
@app.put("/items/{item_id}")
async def update_item(
*,
item_id: int,
item: Annotated[
Item,
Body(
examples=[
{
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
},
{
"name": "Bar",
"price": "35.4",
},
{
"name": "Baz",
"price": "thirty five point four",
},
],
),
],
):
results = {"item_id": item_id, "item": item}
return results
참고
위 코드에서
*를 파라미터 목록 맨 앞에 두면, 그 뒤의 파라미터들은 전부 **키워드 전용(keyword-only)**이 돼요. 위치 인자로 잘못 전달하는 실수를 막아 주는 문법이에요. 이건 지금 스킵해도 괜찮지만, 코드에서 마주치면 "아, 위치로 못 넣게 막는 거구나" 하고 넘어가면 돼요.
Docs UI에서의 예시
예시를 하나만 넣으면 Swagger UI의 "Example Value"에 그 값이 표시돼요. 여러 개를 넣으면 각각의 예시를 사용자가 골라볼 수 있게 돼요.
openapi_examples 파라미터 사용하기
examples와는 별개로, OpenAPI 전용 examples를 더 풍부하게 지정하는 방법도 있어요. 바로 openapi_examples 파라미터예요. 이것도 위에서 본 Path(), Query(), Header(), Cookie(), Body(), Form(), File() 어디에나 쓸 수 있어요.
openapi_examples는 dict인데, 각 키가 예시의 이름이고, 각 값이 다시 하나의 예시 dict예요. 예시마다 summary(요약), description(설명), value(실제 값)를 붙일 수 있어서, 예시들에 설명을 달아 보여주기 좋아요.
from typing import Annotated
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
@app.put("/items/{item_id}")
async def update_item(
*,
item_id: int,
item: Annotated[
Item,
Body(
openapi_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",
},
},
"invalid": {
"summary": "Invalid data is rejected with an error",
"value": {
"name": "Baz",
"price": "thirty five point four",
},
},
},
),
],
):
results = {"item_id": item_id, "item": item}
return results
이 예시의 흐름을 따라가 보면 재미있어요.
normal은 그냥 정상적인 숫자price를 보여주는 예시예요.converted는price가 문자열"35.4"로 와도 FastAPI가 숫자로 자동 변환한다는 걸 보여줘요.invalid는 알아듣지 못하는 문자열"thirty five point four"를 보내면 검증에 실패한다는 걸 보여줘요.
이렇게 하면 문서 UI에서 각 예시를 선택했을 때, 예시마다 이름과 설명까지 함께 보여서 사용자가 훨씬 이해하기 쉬워져요.
참고
openapi_examples는Body()등에 주는 FastAPI의 파라미터이고, 예시의 형식(각 예시의value)을 OpenAPI 명세에 맞게 정리해 주는 역할을 해요.examples는 문서 라이브러리에 직접 전달되는 방식이라 동작이 조금 다르긴 한데, 결과적으로 둘 다 문서에 예시가 보이게 해 주죠.
기본 동작과 기술적인 세부 사항
이 페이지를 보면서 "왜 examples와 openapi_examples가 따로 있을까?" 하는 궁금증이 들 수 있어요. 간단히 배경을 정리하면 이래요.
- FastAPI 0.99.0 이전에는 OpenAPI 2(그리고 그 안의 JSON Schema 드래프트)를 써서,
examples가 JSON Schema 안에 깔끔하게 들어가지 못했어요. - 지금은 FastAPI가 OpenAPI 3.1.0을 쓰고, 이 OpenAPI가 JSON Schema 2020-12를 사용하며, Swagger UI도 5.0.0 이상이라서 상황이 훨씬 일관적이에요. 이제
examples가 JSON Schema 안에 제대로 포함돼요.
즉, 문서 도구들이 예시를 JSON Schema의 일부로 인식하느냐, 아니면 OpenAPI 전용 필드로 인식하느냐에 따라 두 가지 방법이 나뉘어요. examples는 JSON Schema의 필드로 들어가고, openapi_examples는 OpenAPI가 정의한 examples 형식으로 정리돼요.
참고
Body()와File(),Form()은 OpenAPI의Request Body Object에서content필드의Media Type Object에 해당하는 자리에 예시를 넣어요. 구체적인 명세가 궁금하다면 OpenAPI Specification을 참고해도 좋아요.
더 알아보기 (Learn more)
- 공식문서: Declare Request Example Data
- Pydantic 모델 확장: Body - Multiple Parameters
- OpenAPI 명세: Request Body Object