FastAPI + Dependency Injector

от автора

Привет,

Я выпустил новую версию Dependency Injector 4.4. Она позволяет использовать Dependency Injector вместе с FastAPI. В этом посте покажу как это работает.

Основная задача интеграции: подружить директиву Depends FastAPI c маркерами Provide и Provider Dependency Injector’a.

Из коробки до версии DI 4.4 это не работало. FastAPI использует типизацию и Pydantic для валидации входных параметров и ответа. Маркеры Dependency Injector’а приводили его в недоумение.

Решение пришло после изучения внутренностей FastAPI. Пришлось сделать нескольких изменений в модуле связывания (wiring) Dependency Injector’а. Директива Depends теперь работает вместе с маркерами Provide и Provider.

Пример

Создайте файл fastapi_di_example.py и поместите в него следующие строки:

import sys  from fastapi import FastAPI, Depends from dependency_injector import containers, providers from dependency_injector.wiring import inject, Provide   class Service:     async def process(self) -> str:         return 'Ok'   class Container(containers.DeclarativeContainer):      service = providers.Factory(Service)   app = FastAPI()   @app.api_route('/') @inject async def index(service: Service = Depends(Provide[Container.service])):     result = await service.process()     return {'result': result}   container = Container() container.wire(modules=[sys.modules[__name__]]) 

Для того чтобы запустить пример установите зависимости:

pip install fastapi dependency-injector uvicorn 

и запустите uvicorn:

uvicorn fastapi_di_example:app --reload 

В терминале должно будет появится что-то вроде:

INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) INFO:     Started reloader process [11910] using watchgod INFO:     Started server process [11912] INFO:     Waiting for application startup. INFO:     Application startup complete. 

а http://127.0.0.1:8000 должен возвращать:

{     "result": "Ok" } 

Как тестировать?

Создайте рядом файл tests.py и поместите в него следующие строки:

from unittest import mock  import pytest from httpx import AsyncClient  from fastapi_di_example import app, container, Service   @pytest.fixture def client(event_loop):     client = AsyncClient(app=app, base_url='http://test')     yield client     event_loop.run_until_complete(client.aclose())   @pytest.mark.asyncio async def test_index(client):     service_mock = mock.AsyncMock(spec=Service)     service_mock.process.return_value = 'Foo'      with container.service.override(service_mock):         response = await client.get('/')      assert response.status_code == 200     assert response.json() == {'result': 'Foo'} 

Для того чтобы запустить тесты установите зависимости:

pip install pytest pytest-asyncio httpx 

и запустите pytest:

pytest tests.py 

В терминале должно будет появится:

======= test session starts ======= platform darwin -- Python 3.8.3, pytest-5.4.3, py-1.9.0, pluggy-0.13.1 rootdir: ... plugins: asyncio-0.14.0 collected 1 item  tests.py .                                                      [100%]  ======= 1 passed in 0.17s ======= 

Что дает интеграция?

FastAPI — классный фреймворк для построения API. В него встроен базовый механизм dependency injection.

Эта интеграция улучшает работу dependency injection в FastAPI. Она позволяет использовать в нём провайдеры, переопредение, конфиг и ресурсы Dependency Injector’а.

Что дальше?

ссылка на оригинал статьи https://habr.com/ru/post/528634/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *