โก ๐ ๏ธ ๐ง ๐ณ¶
๐ {¶
Warning
๐ฅ ๐ ๐ซ "๐ด" ๐, ๐ ๐ฒ ๐ซ ๐ช ๐.
๐ ๐ช โ ๐ operationId
โ๏ธ ๐ โก ๐ ๏ธ โฎ๏ธ ๐ข operation_id
.
๐ ๐ โ๏ธ โ ๐ญ ๐ โซ๏ธ ๐ ๐ ๐ ๏ธ.
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/", operation_id="some_specific_id_you_define")
async def read_items():
return [{"item_id": "Foo"}]
โ๏ธ โก ๐ ๏ธ ๐ข ๐ {¶
๐ฅ ๐ ๐ โ๏ธ ๐ ๐' ๐ข ๐ operationId
โ, ๐ ๐ช ๐ ๐คญ ๐ ๐ซ & ๐ ๐ โก ๐ ๏ธ operation_id
โ๏ธ ๐ซ APIRoute.name
.
๐ ๐ โซ๏ธ โฎ๏ธ โ ๐ ๐ โก ๐ ๏ธ.
from fastapi import FastAPI
from fastapi.routing import APIRoute
app = FastAPI()
@app.get("/items/")
async def read_items():
return [{"item_id": "Foo"}]
def use_route_names_as_operation_ids(app: FastAPI) -> None:
"""
Simplify operation IDs so that generated API clients have simpler function
names.
Should be called only after all routes have been added.
"""
for route in app.routes:
if isinstance(route, APIRoute):
route.operation_id = route.name # in this case, 'read_items'
use_route_names_as_operation_ids(app)
Tip
๐ฅ ๐ โ ๐ค app.openapi()
, ๐ ๐ โน operationId
โ โญ ๐.
Warning
๐ฅ ๐ ๐, ๐ โ๏ธ โ ๐ญ ๐ 1๏ธโฃ ๐ โก ๐ ๏ธ ๐ข โ๏ธ ๐ ๐.
๐ฅ ๐ซ ๐ ๐น (๐ ๐).
๐ซ โช๏ธโก๏ธ ๐¶
๐ซ โก ๐ ๏ธ โช๏ธโก๏ธ ๐ ๐ ๐ (& โก๏ธ, โช๏ธโก๏ธ ๐ง ๐งพ โ๏ธ), โ๏ธ ๐ข include_in_schema
& โ โซ๏ธ False
:
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/", include_in_schema=False)
async def read_items():
return [{"item_id": "Foo"}]
๐ง ๐ โช๏ธโก๏ธ #๏ธโฃ¶
๐ ๐ช ๐ โธ โ๏ธ โช๏ธโก๏ธ #๏ธโฃ โก ๐ ๏ธ ๐ข ๐.
โ \f
(๐ "๐จ ๐ผ" ๐ฆน) ๐ค FastAPI ๐ ๐ข โ๏ธ ๐ ๐ โ.
โซ๏ธ ๐ ๐ซ ๐ฆ ๐ ๐งพ, โ๏ธ ๐ ๐งฐ (โ ๐) ๐ ๐ช โ๏ธ ๐.
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.post("/items/", response_model=Item, summary="Create an item")
async def create_item(item: Item):
"""
Create an item with all the information:
- **name**: each item must have a name
- **description**: a long description
- **price**: required
- **tax**: if the item doesn't have tax, you can omit this
- **tags**: a set of unique tag strings for this item
\f
:param item: User input.
"""
return item
๐ ๐จ¶
๐ ๐ฒ โ๏ธ ๐ โ ๐ฃ response_model
& status_code
โก ๐ ๏ธ.
๐ ๐ฌ ๐ ๐ ๐ ๐จ โก ๐ ๏ธ.
๐ ๐ช ๐ฃ ๐ ๐จ โฎ๏ธ ๐ซ ๐ท, ๐ ๐, โ๏ธ.
๐ค ๐ ๐ ๐ฅ ๐งพ ๐ โซ๏ธ, ๐ ๐ช โ โซ๏ธ ๐ ๐จ ๐.
๐ โ¶
๐โ ๐ ๐ฃ โก ๐ ๏ธ ๐ ๐ธ, FastAPI ๐ ๐ ๐ ๐ ๐ ๐ โก ๐ ๏ธ ๐ ๐ ๐.
๐ก โน
๐ ๐ง โซ๏ธ ๐ค ๐ ๏ธ ๐.
โซ๏ธ โ๏ธ ๐ โน ๐ โก ๐ ๏ธ & โ๏ธ ๐ ๐ง ๐งพ.
โซ๏ธ ๐ tags
, parameters
, requestBody
, responses
, โ๏ธ.
๐ โก ๐ ๏ธ-๐ฏ ๐ ๐ ๐ ๐ ๐ FastAPI, โ๏ธ ๐ ๐ช โ โซ๏ธ.
Tip
๐ ๐ ๐ โ โ.
๐ฅ ๐ ๐ด ๐ช ๐ฃ ๐ ๐จ, ๐ ๐ช ๐ โซ๏ธ โฎ๏ธ ๐ ๐จ ๐.
๐ ๐ช โ ๐ ๐ โก ๐ ๏ธ โ๏ธ ๐ข openapi_extra
.
๐ โ¶
๐ openapi_extra
๐ช ๐, ๐ผ, ๐ฃ ๐ โ:
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/", openapi_extra={"x-aperture-labs-portal": "blue"})
async def read_items():
return [{"item_id": "portal-gun"}]
๐ฅ ๐ ๐ ๐ง ๐ ๏ธ ๐ฉบ, ๐ โ ๐ ๐ฆ ๐ ๐ ๐ฏ โก ๐ ๏ธ.
& ๐ฅ ๐ ๐ ๐ ๐ ( /openapi.json
๐ ๐ ๏ธ), ๐ ๐ ๐ ๐ โ ๐ ๐ฏ โก ๐ ๏ธ ๐โโ๏ธ:
{
"openapi": "3.0.2",
"info": {
"title": "FastAPI",
"version": "0.1.0"
},
"paths": {
"/items/": {
"get": {
"summary": "Read Items",
"operationId": "read_items_items__get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
}
},
"x-aperture-labs-portal": "blue"
}
}
}
}
๐ ๐ โก ๐ ๏ธ ๐¶
๐ openapi_extra
๐ ๐ ๐ โฎ๏ธ ๐ ๐ ๐ ๐ โก ๐ ๏ธ.
, ๐ ๐ช ๐ฎ ๐ ๐ฝ ๐ ๐ ๐.
๐ผ, ๐ ๐ช ๐ญ โ & โ ๐จ โฎ๏ธ ๐ ๐ ๐, ๐ต โ๏ธ ๐ง โ FastAPI โฎ๏ธ Pydantic, โ๏ธ ๐ ๐ช ๐ ๐ฌ ๐จ ๐ ๐.
๐ ๐ช ๐ โฎ๏ธ openapi_extra
:
from fastapi import FastAPI, Request
app = FastAPI()
def magic_data_reader(raw_body: bytes):
return {
"size": len(raw_body),
"content": {
"name": "Maaaagic",
"price": 42,
"description": "Just kiddin', no magic here. โจ",
},
}
@app.post(
"/items/",
openapi_extra={
"requestBody": {
"content": {
"application/json": {
"schema": {
"required": ["name", "price"],
"type": "object",
"properties": {
"name": {"type": "string"},
"price": {"type": "number"},
"description": {"type": "string"},
},
}
}
},
"required": True,
},
},
)
async def create_item(request: Request):
raw_body = await request.body()
data = magic_data_reader(raw_body)
return data
๐ ๐ผ, ๐ฅ ๐ซ ๐ฃ ๐ Pydantic ๐ท. ๐, ๐จ ๐ช ๐ซ ๐ป ๐ป, โซ๏ธ โ ๐ bytes
, & ๐ข magic_data_reader()
๐ ๐ ๐ป โซ๏ธ ๐.
๐, ๐ฅ ๐ช ๐ฃ ๐ ๐ ๐จ ๐ช.
๐ ๐ ๐ ๐¶
โ๏ธ ๐ ๐ ๐ฑ, ๐ ๐ช โ๏ธ Pydantic ๐ท ๐ฌ ๐ป ๐ ๐ โคด๏ธ ๐ ๐ ๐ ๐ ๐ โก ๐ ๏ธ.
& ๐ ๐ช ๐ ๐ฅ ๐ฝ ๐ ๐จ ๐ซ ๐ป.
๐ผ, ๐ ๐ธ ๐ฅ ๐ซ โ๏ธ FastAPI ๐ ๏ธ ๐ ๏ธ โ ๐ป ๐ โช๏ธโก๏ธ Pydantic ๐ท ๐ซ ๐ง ๐ฌ ๐ป. ๐, ๐ฅ ๐ฃ ๐จ ๐ ๐ ๐, ๐ซ ๐ป:
from typing import List
import yaml
from fastapi import FastAPI, HTTPException, Request
from pydantic import BaseModel, ValidationError
app = FastAPI()
class Item(BaseModel):
name: str
tags: List[str]
@app.post(
"/items/",
openapi_extra={
"requestBody": {
"content": {"application/x-yaml": {"schema": Item.model_json_schema()}},
"required": True,
},
},
)
async def create_item(request: Request):
raw_body = await request.body()
try:
data = yaml.safe_load(raw_body)
except yaml.YAMLError:
raise HTTPException(status_code=422, detail="Invalid YAML")
try:
item = Item.model_validate(data)
except ValidationError as e:
raise HTTPException(status_code=422, detail=e.errors())
return item
๐, ๐ ๐ฅ ๐ซ โ๏ธ ๐ข ๐ ๏ธ ๐ ๏ธ, ๐ฅ โ๏ธ Pydantic ๐ท โ ๐ ๐ป ๐ ๐ฝ ๐ ๐ฅ ๐ ๐จ ๐.
โคด๏ธ ๐ฅ โ๏ธ ๐จ ๐, & โ ๐ช bytes
. ๐ โ ๐ FastAPI ๐ ๐ซ ๐ ๐ป ๐จ ๐ ๐ป.
& โคด๏ธ ๐ ๐, ๐ฅ ๐ป ๐ ๐ ๐ ๐, & โคด๏ธ ๐ฅ ๐ โ๏ธ ๐ Pydantic ๐ท โ ๐ ๐:
from typing import List
import yaml
from fastapi import FastAPI, HTTPException, Request
from pydantic import BaseModel, ValidationError
app = FastAPI()
class Item(BaseModel):
name: str
tags: List[str]
@app.post(
"/items/",
openapi_extra={
"requestBody": {
"content": {"application/x-yaml": {"schema": Item.model_json_schema()}},
"required": True,
},
},
)
async def create_item(request: Request):
raw_body = await request.body()
try:
data = yaml.safe_load(raw_body)
except yaml.YAMLError:
raise HTTPException(status_code=422, detail="Invalid YAML")
try:
item = Item.model_validate(data)
except ValidationError as e:
raise HTTPException(status_code=422, detail=e.errors())
return item
Tip
๐ฅ ๐ฅ ๐ค-โ๏ธ ๐ Pydantic ๐ท.
โ๏ธ ๐ ๐, ๐ฅ ๐ช โ๏ธ โ โซ๏ธ ๐ ๐.