Как работает монтирование приложений FastAPI?

По определенным причинам мы выбрали FastAPI, чтобы использовать его в качестве внутреннего уровня нашего многофункционального - модульное производство. Одной из его привлекательных особенностей является подпрограмма, которая помогает нам разделить различные модули, чтобы сделать их более модульными. Но мы обеспокоены некоторыми возможными недостатками, которые отсутствуют в официальной документации. Существует значительное количество общих вещей — например, данные, сервисы и т. д. — которые нам нужно разделить между основным модулем и подмодулем с помощью плагинов, промежуточных программ и внедрения зависимостей. Возникают вопросы: Достаточно ли хороша эта функция для отдельных модулей? и так далее: Наследуют ли вспомогательные приложения промежуточное ПО, подключаемые модули и внедрение зависимостей от родительского приложения?

спасибо, что поделились своим опытом.

пример кода в официальной документации

from fastapi import FastAPI

app = FastAPI()


@app.get("/app")
def read_main():
    return {"message": "Hello World from main app"}


subapi = FastAPI()


@subapi.get("/sub")
def read_sub():
    return {"message": "Hello World from sub API"}


app.mount("/subapi", subapi)

person Ahad Rafat Talebi    schedule 12.10.2020    source источник


Ответы (1)


Я думаю, что документация довольно ясна об этом.

Монтаж означает добавление полностью независимого приложения.

Как бы то ни было, давайте продолжим с вашего примера.

Вот что мы получили для маршрутов нашего субапи.

[{"path":route.path} for route in subapi.routes] = [
     {'path': '/openapi.json'},
     {'path': '/docs'},
     {'path': '/docs/oauth2-redirect'},
     {'path': '/redoc'},
     {'path': '/sub'}
     ]

Это то, что мы получили для маршрутов приложения.

[{"path":route.path} for route in app.routes] = [{'path': '/openapi.json'},
     {'path': '/docs'},
     {'path': '/docs/oauth2-redirect'},
     {'path': '/redoc'},
     {'path': '/app'},
     {'path': '/subapi'}
     ]

Это довольно интересно, потому что наш subapi не унаследовал /app, давайте продолжим и сделаем все интереснее, давайте запустим наше приложение с помощью одной команды

uvicorn my_app_name:app 
  • Как и ожидалось, документация нашего приложения находится в /docs.

  • Также у нас есть документация по subapi в /subapi/docs, здесь не интересно.

Итак, чего нам следует ожидать, когда мы добавим это?

subapi.mount("/app", app)

Давайте запустим его снова, но на этот раз вызовем subapi.

uvicorn my_app_name:subapi

Что мы ожидаем увидеть?

  • По умолчанию у нас должна быть документация subapi в /docs
  • Документация приложения в /app/docs

Да, мы правы, но дальше начинается самое интересное.

Теперь у нас есть приложение наподобие Матрешки.

Когда мы отправляем запрос на /app/subapi/sub (напомните, что мы запускали наше приложение с uvicorn my_app_name:subapi)

curl http://127.0.0.1:8000/app/subapi/sub

Out: {"message":"Hello World from sub API"}

Кажется, это работает нормально, но давайте попробуем еще.

А как насчет /app/subapi/app/subapi/app/subapi/app/subapi/app/subapi/app/app

curl http://127.0.0.1:8000/app/subapi/app/subapi/app/subapi/app/subapi/app/subapi/app/app

Out: {"message":"Hello World from main app"}

Вы растеряны? Не будь, позвольте мне объяснить.

Когда вы монтируете субприложение, FastAPI позаботится о смонтированном приложении, используя механизм из спецификации ASGI, который называется root_path.

Что делает root_path и почему приведенный выше пример сработал?

Проще говоря, root_path говорит, что вы можете добраться до всех маршрутов, которые вы определили в своем app.routes, из вашего root_path, давайте представим это.

Теперь нашему root_path /app

/app/

Добавим subapi, и он станет нашим root_path.

/app/subapi/

Давайте снова добавим приложение, и оно станет нашим root_path

/app/subapi/app
  • Примечание. Приведенный выше пример работал, потому что мы смонтировали два приложения вместе.

Вы не удовлетворены, и вы говорите, что если я добавлю промежуточное программное обеспечение, что произойдет?

Легко ответить, он не унаследует.

Позвольте мне объяснить это на простом примере, я собираюсь добавить промежуточное программное обеспечение для моего subapi.

from fastapi.middleware.cors import CORSMiddleware

subapi.add_middleware(CORSMiddleware)

Все данные для вашего приложения находятся внутри __dict__

Таким образом, мы можем легко обнаружить разницу, проверив ключ «user_middleware».

subapi.__dict__['user_middleware'] = [Middleware(CORSMiddleware)]
app.__dict__['user_middleware'] = []

Все остальные вещи, которые вы добавляете и т. д., будут работать независимо, потому что это совершенно разные приложения, поэтому вы будете безопасно использовать монтирование.

Вывод

  • Да, они будут работать независимо.
person Yagiz Degirmenci    schedule 12.10.2020
comment
большое спасибо за ваш полный ответ. Я мог бы извлечь больше уроков из вашего ответа, чем я просил. кажется, я должен упаковать свои зависимости, чтобы внедрить их в каждое из дополнительных приложений отдельно. - person Ahad Rafat Talebi; 13.10.2020
comment
Пожалуйста! Я рад, что это помогло. Да, в некоторых случаях это довольно полезно, я точно не знаю, каков ваш вариант использования, но, похоже, вы хотите использовать много промежуточного программного обеспечения и внедрения зависимостей, возможно, вам следует подумать о создании собственного класс APIRouter - person Yagiz Degirmenci; 13.10.2020
comment
Кажется, хорошее предложение. он может интегрировать большинство промежуточных продуктов, которые я попробую. спасибо еще раз. - person Ahad Rafat Talebi; 13.10.2020