|
| 1 | +# Title |
| 2 | +Данный шаблон был разработан для одной цели - облегчения и повышения качества |
| 3 | +выполненых тестовых заданий в рамках **FastAPI**. |
| 4 | + |
| 5 | +# Quick start |
| 6 | +Для тех кто уже знаком с реализацией и всеми деталями - могут приступить к установке. |
| 7 | +## Enviroments |
| 8 | +Необходимо заполнить **.env.sample** и в последствии перемеиновать его в **.env** |
| 9 | +```python |
| 10 | +# .env.sample |
| 11 | +POSTGRES_PASSWORD=password # Пароль от базы данных (Настройка) |
| 12 | +DB_PASSWORD=password # Пароль от базы данных (Использование) |
| 13 | +TEST_POSTGRES_PASSWORD=password # Пароль от тестовой базы данный (Настройка) |
| 14 | +TEST_DB_PASSWORD=password # Пароль от тестовой базы данных (Использование) |
| 15 | +``` |
| 16 | +## Docker |
| 17 | +Шаблон находится под системой управления и контеризации - **Docker**. |
| 18 | +Если у вас нет Docker - вы можете установить его с официального сайта: [Docker](https://www.docker.com/get-started/) |
| 19 | +- Вам необходимо сделать "Билд" |
| 20 | +```bash |
| 21 | +docker compose build |
| 22 | +``` |
| 23 | +- Вам необходимо запустить окружение |
| 24 | +```bash |
| 25 | +docker compose up |
| 26 | +``` |
| 27 | +- После успешного запуска приложение будет доступно по адрессу: http://localhost:8080 |
| 28 | +- Grafana: http://localhost:3000 |
| 29 | +- Flower: http://localhost:5555 |
| 30 | + |
| 31 | +# View |
| 32 | +Обзор и детали данного шаблона |
| 33 | +## Найболее используемые |
| 34 | +Найболее используемые конструкции с которыми приходится часто взаимодействовать. |
| 35 | +### Registration Routers |
| 36 | +- В каждом приложений необходимо инициализировать router |
| 37 | +```python |
| 38 | +# api/users/views.py |
| 39 | +from fastapi import APIRouter |
| 40 | + |
| 41 | + |
| 42 | +router = APIRouter( |
| 43 | + prefix='/users', |
| 44 | + tags=['Users'], |
| 45 | + ) |
| 46 | +``` |
| 47 | +- Затем зарегистрировать роутер |
| 48 | +```python |
| 49 | +# api_v1/routers.py |
| 50 | +from api_v1.users.views import router as users |
| 51 | +from config import settings |
| 52 | + |
| 53 | + |
| 54 | +# В этой функции нужно по порядку регистрировать routers |
| 55 | +def register_routers(app: FastAPI) -> None: |
| 56 | + app.include_router( |
| 57 | + router=users, |
| 58 | + prefix=settings.API_PREFIX, |
| 59 | + ) |
| 60 | +``` |
| 61 | +После регистрации данные маршруты будут доступны. |
| 62 | + |
| 63 | +### Registration Logs |
| 64 | +- Логи захватывают все исключения возникшие в системе |
| 65 | +и с помошью дисперичизации распределяется по нужным **file.log** |
| 66 | +```python |
| 67 | +# app_includes/logs_errors.py |
| 68 | +from fastapi import FastAPI |
| 69 | +from api_v1.exeptions import ValidationError |
| 70 | + |
| 71 | + |
| 72 | +# В данной функции регистрируются все исключения для захватывания Логами |
| 73 | +def register_errors(app: FastAPI) -> None: |
| 74 | + @app.exception_handler(ValidationError) |
| 75 | + async def validation_error_handler( |
| 76 | + request: Request, |
| 77 | + exc: ValidationError, |
| 78 | + ): |
| 79 | + logger.opt(exception=True).warning(exc) |
| 80 | + response = dict( |
| 81 | + status=False, |
| 82 | + error_code=exc.status_code, |
| 83 | + message=exc.detail, |
| 84 | + ) |
| 85 | + return JSONResponse(response) |
| 86 | +``` |
| 87 | +- Если вы пишете пользовательское исключение например: |
| 88 | +```python |
| 89 | +from starlette.exceptions import HTTPException |
| 90 | + |
| 91 | + |
| 92 | +class ValidationError(HTTPException): |
| 93 | + |
| 94 | +pass |
| 95 | +``` |
| 96 | +То вам нужно его зарегистрировать как было показанно выше, |
| 97 | +иначе logs не смогут выявить данное исключение и данные будут утеряны. |
| 98 | + |
| 99 | +### Registration Middlaware |
| 100 | +- Для регистрации Middlaware вам нужно добавить его в функцию |
| 101 | +```python |
| 102 | +from fastapi.middleware.cors import CORSMiddleware |
| 103 | +from fastapi import FastAPI |
| 104 | + |
| 105 | +from config import settings |
| 106 | + |
| 107 | + |
| 108 | +# Данная функция регистрирует все middleware |
| 109 | +def register_middlewares(app: FastAPI) -> None: |
| 110 | + app.add_middleware( |
| 111 | + CORSMiddleware, |
| 112 | + allow_origins=[ |
| 113 | + settings.CURRENT_ORIGIN, |
| 114 | + ], |
| 115 | + allow_credentials=True, |
| 116 | + allow_methods=['*'], |
| 117 | + allow_headers=['*'], |
| 118 | + ) |
| 119 | +``` |
| 120 | +- При появлении новых middleware добавляйте их по порядку в эту функцию |
| 121 | + |
| 122 | +### Celery |
| 123 | +- Для регистрации task вам нужно создать файл с именем **tasks.py** в вашем приложении: |
| 124 | +```python |
| 125 | +# api_v1/users/tasks.py |
| 126 | +from config import celery_app |
| 127 | +import asyncio |
| 128 | + |
| 129 | + |
| 130 | +@celery_app.task |
| 131 | +async def time_sleep_task(): |
| 132 | + """ |
| 133 | + Тестовая задача для Celery |
| 134 | + """ |
| 135 | + await asyncio.sleep(2.0) |
| 136 | + return 'Task is done' |
| 137 | +``` |
| 138 | +- Затем добавить этот файл в список пакетов Celery |
| 139 | +```python |
| 140 | +# confin.celery.connection.py |
| 141 | + |
| 142 | +app = Celery(__name__) |
| 143 | +app.conf.broker_url = settings.rabbit.broker_url |
| 144 | +# Регистрация до окружения где находится tasks.py |
| 145 | +app.autodiscover_tasks(packages=['api_v1.users']) |
| 146 | +``` |
| 147 | +- После этих действий ваша task будет зарегистрирована |
| 148 | + |
| 149 | +### Test |
| 150 | +- Для тестирования у вас есть тестовая база данных, а так же |
| 151 | +уже инициализированный отдельный клиент. |
| 152 | +Cпособ реализации в **api_v1/tests/conftest.py** |
| 153 | +- Что бы написать тестовую функцию которой нужен доступ к API, |
| 154 | +вам нужно использовать fixture - client. |
| 155 | +> [!NOTE] |
| 156 | +> Для асинхронных тестов используйте **@pytest.mark.asyncio** |
| 157 | +
|
| 158 | +```python |
| 159 | +# api_v1.tests.test_users.py |
| 160 | +import pytest |
| 161 | + |
| 162 | + |
| 163 | +@pytest.mark.asyncio |
| 164 | +async def test_get_user_error(client: AsyncClient): |
| 165 | + response = await client.get( |
| 166 | + '/users/get', |
| 167 | + ) |
| 168 | + assert response.status_code == 400 |
| 169 | +``` |
| 170 | +- Для запуска используйте команду |
| 171 | +```bash |
| 172 | +pytest |
| 173 | +``` |
0 commit comments