Додаткова конфігурація операцій шляху¶
🌐 Переклад ШІ та людьми
Цей переклад виконано ШІ під керівництвом людей. 🤝
Можливі помилки через неправильне розуміння початкового змісту або неприродні формулювання тощо. 🤖
Ви можете покращити цей переклад, допомігши нам краще спрямовувати AI LLM.
OpenAPI operationId¶
Попередження
Якщо ви не «експерт» з OpenAPI, імовірно, вам це не потрібно.
Ви можете встановити OpenAPI 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"}]
🤓 Other versions and variants
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¶
Якщо ви хочете використовувати назви функцій ваших API як 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)
🤓 Other versions and variants
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)
Порада
Якщо ви вручну викликаєте app.openapi(), оновіть значення operationId до цього.
Попередження
Якщо ви робите це, переконайтеся, що кожна з ваших функцій операцій шляху має унікальну назву.
Навіть якщо вони в різних модулях (файлах Python).
Виключення з OpenAPI¶
Щоб виключити операцію шляху зі згенерованої Схеми OpenAPI (а отже, і з автоматичних систем документації), використайте параметр 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"}]
🤓 Other versions and variants
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/", include_in_schema=False)
async def read_items():
return [{"item_id": "Foo"}]
Розширений опис із docstring¶
Ви можете обмежити кількість рядків із docstring функції операції шляху, що використовуються для OpenAPI.
Додавання \f (екранованого символу «form feed») змусить FastAPI обрізати вивід для OpenAPI в цій точці.
Це не з’явиться в документації, але інші інструменти (такі як Sphinx) зможуть використати решту.
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
tags: set[str] = set()
@app.post("/items/", summary="Create an item")
async def create_item(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 для операції шляху.
Це визначає метадані про основну відповідь операції шляху.
Також можна оголосити додаткові відповіді з їхніми моделями, кодами статусу тощо.
У документації є цілий розділ про це, ви можете прочитати його тут: Додаткові відповіді в OpenAPI.
Додатково в OpenAPI¶
Коли ви оголошуєте операцію шляху у своєму застосунку, FastAPI автоматично генерує відповідні метадані про цю операцію шляху для включення в Схему OpenAPI.
Технічні деталі
У специфікації OpenAPI це називається Об'єкт Operation.
Він містить усю інформацію про операцію шляху і використовується для побудови автоматичної документації.
Він включає tags, parameters, requestBody, responses тощо.
Цю OpenAPI-схему, специфічну для операції шляху, зазвичай генерує FastAPI автоматично, але ви також можете її розширити.
Порада
Це низькорівнева точка розширення.
Якщо вам потрібно лише оголосити додаткові відповіді, зручніше зробити це через Додаткові відповіді в OpenAPI.
Ви можете розширити OpenAPI-схему для операції шляху, використовуючи параметр openapi_extra.
Розширення OpenAPI¶
openapi_extra може бути корисним, наприклад, для оголошення OpenAPI Extensions:
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"}]
🤓 Other versions and variants
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"}]
Якщо ви відкриєте автоматичну документацію API, ваше розширення з’явиться внизу конкретної операції шляху.

І якщо ви відкриєте згенерований OpenAPI (за адресою /openapi.json у вашому API), ви також побачите своє розширення як частину конкретної операції шляху:
{
"openapi": "3.1.0",
"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 для операції шляху¶
Словник у openapi_extra буде глибоко об’єднано з автоматично згенерованою OpenAPI-схемою для операції шляху.
Тож ви можете додати додаткові дані до автоматично згенерованої схеми.
Наприклад, ви можете вирішити читати та перевіряти запит власним кодом, не використовуючи автоматичні можливості FastAPI з Pydantic, але все ж захотіти визначити запит у Схемі OpenAPI.
Ви можете зробити це за допомогою 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
🤓 Other versions and variants
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. Насправді тіло запиту навіть не розібрано як JSON, воно читається безпосередньо як bytes, а функція magic_data_reader() відповідатиме за його розбір певним чином.
Водночас ми можемо оголосити очікувану схему для тіла запиту.
Власний тип вмісту OpenAPI¶
Використовуючи той самий прийом, ви можете застосувати модель Pydantic, щоб визначити Схему JSON, яка потім включається в користувацький розділ OpenAPI-схеми для операції шляху.
І ви можете зробити це, навіть якщо тип даних у запиті - не JSON.
Наприклад, у цьому застосунку ми не використовуємо вбудовану функціональність FastAPI для отримання Схеми JSON з моделей Pydantic і не використовуємо автоматичну валідацію для JSON. Насправді ми оголошуємо тип вмісту запиту як YAML, а не JSON:
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(include_url=False))
return item
🤓 Other versions and variants
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(include_url=False))
return item
Попри те, що ми не використовуємо типову вбудовану функціональність, ми все одно використовуємо модель Pydantic, щоб вручну згенерувати Схему JSON для даних, які хочемо отримати у форматі YAML.
Потім ми працюємо із запитом безпосередньо і отримуємо тіло як bytes. Це означає, що FastAPI навіть не намагатиметься розібрати корисне навантаження запиту як JSON.
Далі у нашому коді ми безпосередньо розбираємо цей YAML-вміст і знову використовуємо ту саму модель Pydantic, щоб перевірити YAML-вміст:
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(include_url=False))
return item
🤓 Other versions and variants
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(include_url=False))
return item
Порада
Тут ми перевикористовуємо ту саму модель Pydantic.
Але так само ми могли б перевіряти дані іншим способом.