Більші застосунки - кілька файлів¶
🌐 Переклад ШІ та людьми
Цей переклад виконано ШІ під керівництвом людей. 🤝
Можливі помилки через неправильне розуміння початкового змісту або неприродні формулювання тощо. 🤖
Ви можете покращити цей переклад, допомігши нам краще спрямовувати AI LLM.
Якщо ви створюєте застосунок або веб-API, рідко вдається вмістити все в один файл.
FastAPI надає зручний інструмент для структурування вашого застосунку, зберігаючи всю гнучкість.
Інформація
Якщо ви прийшли з Flask, це еквівалент «Blueprints» у Flask.
Приклад структури файлів¶
Припустімо, у вас така структура файлів:
.
├── app
│ ├── __init__.py
│ ├── main.py
│ ├── dependencies.py
│ └── routers
│ │ ├── __init__.py
│ │ ├── items.py
│ │ └── users.py
│ └── internal
│ ├── __init__.py
│ └── admin.py
Порада
Тут кілька файлів __init__.py: по одному в кожному каталозі та підкаталозі.
Саме це дозволяє імпортувати код з одного файлу в інший.
Наприклад, у app/main.py ви можете мати рядок:
from app.routers import items
- Каталог
appмістить усе. І він має порожній файлapp/__init__.py, тож це «пакет Python» (збірка «модулів Python»):app. - Він містить файл
app/main.py. Оскільки він усередині пакета Python (каталог з файлом__init__.py), це «модуль» цього пакета:app.main. - Є також файл
app/dependencies.py, так само якapp/main.py, це «модуль»:app.dependencies. - Є підкаталог
app/routers/з іншим файлом__init__.py, отже це «підпакет Python»:app.routers. - Файл
app/routers/items.pyзнаходиться в пакетіapp/routers/, отже це підмодуль:app.routers.items. - Так само і
app/routers/users.py, це інший підмодуль:app.routers.users. - Є також підкаталог
app/internal/з іншим файлом__init__.py, отже це інший «підпакет Python»:app.internal. - І файл
app/internal/admin.py- ще один підмодуль:app.internal.admin.
Та сама структура файлів з коментарями:
.
├── app # «app» - це пакет Python
│ ├── __init__.py # цей файл робить «app» «пакетом Python»
│ ├── main.py # модуль «main», напр. import app.main
│ ├── dependencies.py # модуль «dependencies», напр. import app.dependencies
│ └── routers # «routers» - це «підпакет Python»
│ │ ├── __init__.py # робить «routers» «підпакетом Python»
│ │ ├── items.py # підмодуль «items», напр. import app.routers.items
│ │ └── users.py # підмодуль «users», напр. import app.routers.users
│ └── internal # «internal» - це «підпакет Python»
│ ├── __init__.py # робить «internal» «підпакетом Python»
│ └── admin.py # підмодуль «admin», напр. import app.internal.admin
APIRouter¶
Припустімо, файл, присвячений обробці лише користувачів, - це підмодуль у /app/routers/users.py.
Ви хочете мати операції шляху, пов'язані з користувачами, відокремлено від решти коду, щоб зберегти порядок.
Але це все одно частина того самого застосунку/веб-API FastAPI (це частина того самого «пакета Python»).
Ви можете створювати операції шляху для цього модуля, використовуючи APIRouter.
Імпортуйте APIRouter¶
Імпортуйте його та створіть «екземпляр» так само, як ви б робили з класом FastAPI:
from fastapi import APIRouter
router = APIRouter()
@router.get("/users/", tags=["users"])
async def read_users():
return [{"username": "Rick"}, {"username": "Morty"}]
@router.get("/users/me", tags=["users"])
async def read_user_me():
return {"username": "fakecurrentuser"}
@router.get("/users/{username}", tags=["users"])
async def read_user(username: str):
return {"username": username}
Операції шляху з APIRouter¶
Потім використовуйте його для оголошення операцій шляху.
Використовуйте його так само, як і клас FastAPI:
from fastapi import APIRouter
router = APIRouter()
@router.get("/users/", tags=["users"])
async def read_users():
return [{"username": "Rick"}, {"username": "Morty"}]
@router.get("/users/me", tags=["users"])
async def read_user_me():
return {"username": "fakecurrentuser"}
@router.get("/users/{username}", tags=["users"])
async def read_user(username: str):
return {"username": username}
Можете думати про APIRouter як про «міні FastAPI».
Підтримуються ті самі опції.
Ті самі parameters, responses, dependencies, tags тощо.
Порада
У цьому прикладі змінна називається router, але ви можете назвати її як завгодно.
Ми включимо цей APIRouter у основний застосунок FastAPI, але спочатку розгляньмо залежності та інший APIRouter.
Залежності¶
Бачимо, що нам знадобляться кілька залежностей, які використовуються в різних місцях застосунку.
Тож помістимо їх у власний модуль dependencies (app/dependencies.py).
Тепер використаємо просту залежність для читання користувацького заголовка X-Token:
from typing import Annotated
from fastapi import Header, HTTPException
async def get_token_header(x_token: Annotated[str, Header()]):
if x_token != "fake-super-secret-token":
raise HTTPException(status_code=400, detail="X-Token header invalid")
async def get_query_token(token: str):
if token != "jessica":
raise HTTPException(status_code=400, detail="No Jessica token provided")
🤓 Other versions and variants
from typing import Annotated
from fastapi import Header, HTTPException
async def get_token_header(x_token: Annotated[str, Header()]):
if x_token != "fake-super-secret-token":
raise HTTPException(status_code=400, detail="X-Token header invalid")
async def get_query_token(token: str):
if token != "jessica":
raise HTTPException(status_code=400, detail="No Jessica token provided")
Tip
Prefer to use the Annotated version if possible.
from fastapi import Header, HTTPException
async def get_token_header(x_token: str = Header()):
if x_token != "fake-super-secret-token":
raise HTTPException(status_code=400, detail="X-Token header invalid")
async def get_query_token(token: str):
if token != "jessica":
raise HTTPException(status_code=400, detail="No Jessica token provided")
Порада
Ми використовуємо вигаданий заголовок, щоб спростити приклад.
Але в реальних випадках ви отримаєте кращі результати, використовуючи інтегровані засоби безпеки.
Інший модуль з APIRouter¶
Припустімо, у вас також є кінцеві точки для обробки «items» у модулі app/routers/items.py.
У вас є операції шляху для:
/items//items/{item_id}
Структура така сама, як у app/routers/users.py.
Але ми хочемо бути розумнішими й трохи спростити код.
Ми знаємо, що всі операції шляху в цьому модулі мають однакові:
- Префікс шляху
prefix:/items. tags: (лише одна мітка:items).- Додаткові
responses. dependencies: усім потрібна залежністьX-Token, яку ми створили.
Тож замість додавання цього до кожної операції шляху, ми можемо додати це до APIRouter.
from fastapi import APIRouter, Depends, HTTPException
from ..dependencies import get_token_header
router = APIRouter(
prefix="/items",
tags=["items"],
dependencies=[Depends(get_token_header)],
responses={404: {"description": "Not found"}},
)
fake_items_db = {"plumbus": {"name": "Plumbus"}, "gun": {"name": "Portal Gun"}}
@router.get("/")
async def read_items():
return fake_items_db
@router.get("/{item_id}")
async def read_item(item_id: str):
if item_id not in fake_items_db:
raise HTTPException(status_code=404, detail="Item not found")
return {"name": fake_items_db[item_id]["name"], "item_id": item_id}
@router.put(
"/{item_id}",
tags=["custom"],
responses={403: {"description": "Operation forbidden"}},
)
async def update_item(item_id: str):
if item_id != "plumbus":
raise HTTPException(
status_code=403, detail="You can only update the item: plumbus"
)
return {"item_id": item_id, "name": "The great Plumbus"}
Оскільки шлях кожної операції шляху має починатися з /, як у:
@router.get("/{item_id}")
async def read_item(item_id: str):
...
...префікс не має містити кінцевий /.
Отже, у цьому випадку префікс - це /items.
Ми також можемо додати список tags та додаткові responses, які застосовуватимуться до всіх операцій шляху, включених у цей router.
І ми можемо додати список dependencies, які буде додано до всіх операцій шляху у router і які виконуватимуться/вирішуватимуться для кожного запиту до них.
Порада
Зверніть увагу, що так само як і для залежностей у декораторах операцій шляху, жодне значення не буде передано вашій функції операції шляху.
У підсумку шляхи предметів тепер:
/items//items/{item_id}
...як ми і планували.
- Вони будуть позначені списком міток, що містить один рядок
"items".- Ці «мітки» особливо корисні для автоматичної інтерактивної документації (за допомогою OpenAPI).
- Усі вони включатимуть наперед визначені
responses. - Для всіх цих операцій шляху список
dependenciesбуде оцінений/виконаний перед ними.- Якщо ви також оголосите залежності в конкретній операції шляху, вони також будуть виконані.
- Спочатку виконуються залежності router'а, потім
dependenciesу декораторі, а потім звичайні параметричні залежності. - Ви також можете додати
Securityзалежності зscopes.
Порада
Наявність dependencies у APIRouter можна використати, наприклад, щоб вимагати автентифікацію для всієї групи операцій шляху. Навіть якщо залежності не додані до кожної з них окремо.
Перевірте
Параметри prefix, tags, responses і dependencies - це (як і в багатьох інших випадках) просто можливість FastAPI, яка допомагає уникати дублювання коду.
Імпортуйте залежності¶
Цей код живе в модулі app.routers.items, у файлі app/routers/items.py.
І нам потрібно отримати функцію залежності з модуля app.dependencies, файлу app/dependencies.py.
Тож ми використовуємо відносний імпорт з .. для залежностей:
from fastapi import APIRouter, Depends, HTTPException
from ..dependencies import get_token_header
router = APIRouter(
prefix="/items",
tags=["items"],
dependencies=[Depends(get_token_header)],
responses={404: {"description": "Not found"}},
)
fake_items_db = {"plumbus": {"name": "Plumbus"}, "gun": {"name": "Portal Gun"}}
@router.get("/")
async def read_items():
return fake_items_db
@router.get("/{item_id}")
async def read_item(item_id: str):
if item_id not in fake_items_db:
raise HTTPException(status_code=404, detail="Item not found")
return {"name": fake_items_db[item_id]["name"], "item_id": item_id}
@router.put(
"/{item_id}",
tags=["custom"],
responses={403: {"description": "Operation forbidden"}},
)
async def update_item(item_id: str):
if item_id != "plumbus":
raise HTTPException(
status_code=403, detail="You can only update the item: plumbus"
)
return {"item_id": item_id, "name": "The great Plumbus"}
Як працюють відносні імпорти¶
Порада
Якщо ви досконало знаєте, як працюють імпорти, перейдіть до наступного розділу нижче.
Одна крапка ., як у:
from .dependencies import get_token_header
означає:
- Починаючи в тому самому пакеті, де знаходиться цей модуль (файл
app/routers/items.py) (каталогapp/routers/)... - знайти модуль
dependencies(уявний файлapp/routers/dependencies.py)... - і з нього імпортувати функцію
get_token_header.
Але такого файлу не існує, наші залежності у файлі app/dependencies.py.
Згадайте, як виглядає структура нашого застосунку/файлів:
Дві крапки .., як у:
from ..dependencies import get_token_header
означають:
- Починаючи в тому самому пакеті, де знаходиться цей модуль (файл
app/routers/items.py) (каталогapp/routers/)... - перейти до батьківського пакета (каталог
app/)... - і там знайти модуль
dependencies(файлapp/dependencies.py)... - і з нього імпортувати функцію
get_token_header.
Це працює правильно! 🎉
Так само, якби ми використали три крапки ..., як у:
from ...dependencies import get_token_header
це б означало:
- Починаючи в тому самому пакеті, де знаходиться цей модуль (файл
app/routers/items.py) (каталогapp/routers/)... - перейти до батьківського пакета (каталог
app/)... - потім перейти до батьківського пакета від того (немає батьківського пакета,
app- верхній рівень 😱)... - і там знайти модуль
dependencies(файлapp/dependencies.py)... - і з нього імпортувати функцію
get_token_header.
Це б посилалося на якийсь пакет вище за app/ з власним файлом __init__.py тощо. Але в нас такого немає. Тож у нашому прикладі це спричинить помилку. 🚨
Але тепер ви знаєте, як це працює, тож можете використовувати відносні імпорти у власних застосунках, незалежно від їхньої складності. 🤓
Додайте користувацькі tags, responses і dependencies¶
Ми не додаємо префікс /items ані tags=["items"] до кожної операції шляху, бо додали їх до APIRouter.
Але ми все ще можемо додати ще tags, які будуть застосовані до конкретної операції шляху, а також додаткові responses, специфічні для цієї операції шляху:
from fastapi import APIRouter, Depends, HTTPException
from ..dependencies import get_token_header
router = APIRouter(
prefix="/items",
tags=["items"],
dependencies=[Depends(get_token_header)],
responses={404: {"description": "Not found"}},
)
fake_items_db = {"plumbus": {"name": "Plumbus"}, "gun": {"name": "Portal Gun"}}
@router.get("/")
async def read_items():
return fake_items_db
@router.get("/{item_id}")
async def read_item(item_id: str):
if item_id not in fake_items_db:
raise HTTPException(status_code=404, detail="Item not found")
return {"name": fake_items_db[item_id]["name"], "item_id": item_id}
@router.put(
"/{item_id}",
tags=["custom"],
responses={403: {"description": "Operation forbidden"}},
)
async def update_item(item_id: str):
if item_id != "plumbus":
raise HTTPException(
status_code=403, detail="You can only update the item: plumbus"
)
return {"item_id": item_id, "name": "The great Plumbus"}
Порада
Остання операція шляху матиме комбінацію міток: ["items", "custom"].
І вона також матиме в документації обидві відповіді: одну для 404 і одну для 403.
Основний FastAPI¶
Тепер розгляньмо модуль app/main.py.
Тут ви імпортуєте і використовуєте клас FastAPI.
Це буде головний файл вашого застосунку, який усе поєднує.
І оскільки більшість вашої логіки тепер житиме у власних модулях, головний файл буде досить простим.
Імпортуйте FastAPI¶
Імпортуйте та створіть клас FastAPI, як зазвичай.
І ми навіть можемо оголосити глобальні залежності, які будуть поєднані із залежностями кожного APIRouter:
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users
app = FastAPI(dependencies=[Depends(get_query_token)])
app.include_router(users.router)
app.include_router(items.router)
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
🤓 Other versions and variants
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users
app = FastAPI(dependencies=[Depends(get_query_token)])
app.include_router(users.router)
app.include_router(items.router)
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
Tip
Prefer to use the Annotated version if possible.
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users
app = FastAPI(dependencies=[Depends(get_query_token)])
app.include_router(users.router)
app.include_router(items.router)
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
Імпортуйте APIRouter¶
Тепер імпортуємо інші підмодулі, що мають APIRouter:
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users
app = FastAPI(dependencies=[Depends(get_query_token)])
app.include_router(users.router)
app.include_router(items.router)
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
🤓 Other versions and variants
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users
app = FastAPI(dependencies=[Depends(get_query_token)])
app.include_router(users.router)
app.include_router(items.router)
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
Tip
Prefer to use the Annotated version if possible.
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users
app = FastAPI(dependencies=[Depends(get_query_token)])
app.include_router(users.router)
app.include_router(items.router)
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
Оскільки файли app/routers/users.py та app/routers/items.py - це підмодулі, що є частиною того самого пакета Python app, ми можемо використати одну крапку . для «відносних імпортів».
Як працює імпорт¶
Розділ:
from .routers import items, users
означає:
- Починаючи в тому самому пакеті, де знаходиться цей модуль (файл
app/main.py) (каталогapp/)... - знайти підпакет
routers(каталогapp/routers/)... - і з нього імпортувати підмодулі
items(файлapp/routers/items.py) іusers(файлapp/routers/users.py)...
Модуль items матиме змінну router (items.router). Це та сама, що ми створили у файлі app/routers/items.py, це об’єкт APIRouter.
Потім ми робимо те саме для модуля users.
Ми також могли б імпортувати їх так:
from app.routers import items, users
Інформація
Перша версія - «відносний імпорт»:
from .routers import items, users
Друга версія - «абсолютний імпорт»:
from app.routers import items, users
Щоб дізнатися більше про пакети й модулі Python, прочитайте офіційну документацію Python про модулі.
Уникайте колізій імен¶
Ми імпортуємо підмодуль items напряму, замість імпорту лише його змінної router.
Це тому, що в підмодулі users також є змінна з назвою router.
Якби ми імпортували один за одним, як:
from .routers.items import router
from .routers.users import router
router з users перезаписав би той, що з items, і ми не змогли б використовувати їх одночасно.
Щоб мати змогу використовувати обидва в одному файлі, ми імпортуємо підмодулі напряму:
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users
app = FastAPI(dependencies=[Depends(get_query_token)])
app.include_router(users.router)
app.include_router(items.router)
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
🤓 Other versions and variants
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users
app = FastAPI(dependencies=[Depends(get_query_token)])
app.include_router(users.router)
app.include_router(items.router)
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
Tip
Prefer to use the Annotated version if possible.
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users
app = FastAPI(dependencies=[Depends(get_query_token)])
app.include_router(users.router)
app.include_router(items.router)
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
Додайте APIRouter для users і items¶
Тепер додаймо router з підмодулів users і items:
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users
app = FastAPI(dependencies=[Depends(get_query_token)])
app.include_router(users.router)
app.include_router(items.router)
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
🤓 Other versions and variants
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users
app = FastAPI(dependencies=[Depends(get_query_token)])
app.include_router(users.router)
app.include_router(items.router)
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
Tip
Prefer to use the Annotated version if possible.
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users
app = FastAPI(dependencies=[Depends(get_query_token)])
app.include_router(users.router)
app.include_router(items.router)
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
Інформація
users.router містить APIRouter у файлі app/routers/users.py.
А items.router містить APIRouter у файлі app/routers/items.py.
За допомогою app.include_router() ми можемо додати кожен APIRouter до основного застосунку FastAPI.
Це включить усі маршрути з цього router'а як частину застосунку.
Технічні деталі
Фактично, всередині для кожної операції шляху, оголошеної в APIRouter, буде створена окрема операція шляху.
Тобто за лаштунками все працюватиме так, ніби це один і той самий застосунок.
Перевірте
Вам не потрібно перейматися продуктивністю під час включення router'ів.
Це займе мікросекунди і відбуватиметься лише під час запуску.
Тож це не вплине на продуктивність. ⚡
Додайте APIRouter з власними prefix, tags, responses і dependencies¶
Уявімо, що ваша організація надала вам файл app/internal/admin.py.
Він містить APIRouter з кількома адміністративними операціями шляху, які організація спільно використовує між кількома проєктами.
Для цього прикладу він буде дуже простим. Але припустімо, що оскільки його спільно використовують з іншими проєктами організації, ми не можемо модифікувати його та додавати prefix, dependencies, tags тощо прямо до APIRouter:
from fastapi import APIRouter
router = APIRouter()
@router.post("/")
async def update_admin():
return {"message": "Admin getting schwifty"}
Але ми все одно хочемо встановити користувацький prefix під час включення APIRouter, щоб усі його операції шляху починалися з /admin, хочемо захистити його за допомогою dependencies, які вже є в цьому проєкті, і хочемо додати tags та responses.
Ми можемо оголосити все це, не змінюючи оригінальний APIRouter, передавши ці параметри до app.include_router():
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users
app = FastAPI(dependencies=[Depends(get_query_token)])
app.include_router(users.router)
app.include_router(items.router)
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
🤓 Other versions and variants
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users
app = FastAPI(dependencies=[Depends(get_query_token)])
app.include_router(users.router)
app.include_router(items.router)
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
Tip
Prefer to use the Annotated version if possible.
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users
app = FastAPI(dependencies=[Depends(get_query_token)])
app.include_router(users.router)
app.include_router(items.router)
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
Таким чином, вихідний APIRouter залишиться без змін, тож ми все ще зможемо спільно використовувати той самий файл app/internal/admin.py з іншими проєктами в організації.
У результаті в нашому застосунку кожна з операцій шляху з модуля admin матиме:
- Префікс
/admin. - Мітку
admin. - Залежність
get_token_header. - Відповідь
418. 🍵
Але це вплине лише на цей APIRouter у нашому застосунку, а не на будь-який інший код, який його використовує.
Наприклад, інші проєкти можуть використовувати той самий APIRouter з іншим методом автентифікації.
Додайте операцію шляху¶
Ми також можемо додавати операції шляху безпосередньо до застосунку FastAPI.
Тут ми це робимо... просто щоб показати, що так можна 🤷:
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users
app = FastAPI(dependencies=[Depends(get_query_token)])
app.include_router(users.router)
app.include_router(items.router)
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
🤓 Other versions and variants
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users
app = FastAPI(dependencies=[Depends(get_query_token)])
app.include_router(users.router)
app.include_router(items.router)
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
Tip
Prefer to use the Annotated version if possible.
from fastapi import Depends, FastAPI
from .dependencies import get_query_token, get_token_header
from .internal import admin
from .routers import items, users
app = FastAPI(dependencies=[Depends(get_query_token)])
app.include_router(users.router)
app.include_router(items.router)
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
@app.get("/")
async def root():
return {"message": "Hello Bigger Applications!"}
і це працюватиме коректно разом з усіма іншими операціями шляху, доданими через app.include_router().
Дуже технічні деталі
Примітка: це дуже технічна деталь, яку ви, ймовірно, можете просто пропустити.
APIRouter не «монтуються», вони не ізольовані від решти застосунку.
Це тому, що ми хочемо включати їхні операції шляху в схему OpenAPI та інтерфейси користувача.
Оскільки ми не можемо просто ізолювати їх і «змонтувати» незалежно від решти, операції шляху «клонуються» (створюються заново), а не включаються безпосередньо.
Перевірте автоматичну документацію API¶
Тепер запустіть ваш застосунок:
$ fastapi dev app/main.py
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
І відкрийте документацію за адресою http://127.0.0.1:8000/docs.
Ви побачите автоматичну документацію API, що включає шляхи з усіх підмодулів, з правильними шляхами (і префіксами) та правильними мітками:

Включайте той самий router кілька разів з різними prefix¶
Ви також можете використовувати .include_router() кілька разів з одним і тим самим router'ом, але з різними префіксами.
Це може бути корисно, наприклад, щоб публікувати той самий API під різними префіксами, наприклад /api/v1 і /api/latest.
Це просунуте використання, яке вам може й не знадобитися, але воно є на випадок, якщо потрібно.
Включіть один APIRouter до іншого¶
Так само як ви можете включити APIRouter у застосунок FastAPI, ви можете включити APIRouter в інший APIRouter, використовуючи:
router.include_router(other_router)
Переконайтеся, що ви робите це до включення router в застосунок FastAPI, щоб операції шляху з other_router також були включені.