Powerful tools for creating and testing APIs
In the world of modern web development, FastAPI has established itself as a powerful and fast framework for creating APIs. However, when working on large projects, developers often face the need to optimize routine processes, improve the code structure and simplify testing. In this article, we will consider a set of tools that will help solve these problems and significantly speed up development on FastAPI.
While going to many interviews, I noticed that many companies actively using FastAPI have developed their own libraries, but there are practically no similar tools with open access and a free license. As an experienced backend developer in Python and Django, I decided to adapt and integrate the most useful and popular solutions for developing REST APIs into FastAPI, based on my experience with Django.
Short term goal: Gather feedback from the community on this idea.
Long-term goal: improve the tool in open source by encouraging large companies to stop developing and maintaining their own proprietary code. Instead, we aim to create an ecosystem where companies not only use a common tool, but actively participate in its improvement by contributing to the open-source project.
Who will benefit from this?
For Python backend developers using or planning to use FastAPI
For teams working on medium to large projects on FastAPI
For developers who want to improve the structure of their FastAPI projects and speed up the development process
For those looking for effective tools for testing FastAPI applications
Why do we need this toolkit?
FastAPI Accelerator is an open-source toolkit built on best practices for REST API development.
The main goal of the presented toolkit is to speed up and simplify the development of projects on FastAPI.
This is achieved by:
Detailed and good documentation.
Providing reusable code for common tasks.
Implementation of a universal manager for working with RDBMS.
ViewSet implementations for quickly creating views with basic business logic.
JWT authentication integrations.
Addition of a convenient admin panel.
Simplify writing and running integration tests for APIs.
Optimizations for working with Alembic for managing migrations in production and test environments.
All these components are interconnected and complement each other, automating routine tasks.
Tool structure
Let's take a look at the main components of our toolkit:
fastapi_accelerator/
├── db/ # Логика взаимодействия с РСУБД
├── pattern/ # Шаблоны для проектов
├── testutils/ # Утилиты для тестирования FastAPI
├── cache.py # Реализация кеширования
├── auth_jwt.py # Аутентификация по JWT
├── exception.py # Обработка исключений
├── middleware.py # Middleware компоненты
├── paginator.py # Реализация пагинации
├── timezone.py # Работа с временными зонами
├── viewset.py # Реализация ViewSet
└── utils.py # Общие утилиты
FastAPI Project Structures
Proper project organization is key to its scalability and ease of support. Here is an example of the recommended FastAPI project structure using FastAPI Accelerator:
Проект/
│
├── app/
│ ├── __init__.py
│ ├── utils.py # Пере используемый функционал для проекта
│ ├── core/ # Содержит основные модули, такие как конфигурация, безопасность и общие зависимости.
│ │ ├── __init__.py
│ │ ├── settings_local.py # Локальные значения для настроек, не должны быть в git, создавать непосредственно на сервере
│ │ ├── config.py # Настройки проекта которые не зависят от внешних настроек
│ │ ├── security.py # Логика безопасности проекта
│ │ ├── db.py # Настройки и сессии базы данных.
│ │ ├── cache.py # Настройки кеширования
│ │ └── dependencies.py
│ │
│ ├── api/ # Содержит все API эндпоинты, разделенные по версиям.
│ │ ├── __init__.py
│ │ └── v1/
│ │ ├── __init__.py
│ │ ├── router.py # Содержит обработчики запросов для указанной версии api
│ │ │
│ │ ├── static/ # Содержит файлы статики, если они нужны
│ │ │ ├── js
│ │ │ ├── css
│ │ │ ├── img
│ │ │ └── html
│ │ │
│ │ ├── logic/ # Содержит бизнес логику
│ │ │ ├── __init__.py
│ │ │ ├── users.py
│ │ │ └── items.py
│ │ │
│ │ ├── schemas/ # Pydantic модели для валидации запросов и ответов.
│ │ │ ├── __init__.py
│ │ │ ├── user.py
│ │ │ └── item.py
│ │ │
│ │ ├── crud/ # Функции для работы с базой данных (Create, Read, Update, Delete).
│ │ │ ├── __init__.py
│ │ │ ├── user.py
│ │ │ └── item.py
│ │ │
│ │ └── tests/ # Директория для тестов.
│ │ ├── __init__.py
│ │ ├── test_users.py
│ │ └── test_items.py
│ │
│ ├── models/ # Определения моделей базы данных (например, SQLAlchemy модели).
│ │ ├── __init__.py
│ │ ├── user.py
│ │ └── item.py
│ │
│ └── fixture/ # Хранит фикстуры для тестирования этого проекта
│ ├── __init__.py
│ ├── items_v1.py # Тестовые записи для БД
│ └── utils.py # Переиспользуемые фикстуры для тестов
│
├── fastapi_accelerator/ # Submodule для переиспользовать
│
├── alembic/ # Директория для миграций базы данных.
│ ├── versions/ # Папка с миграциями
│ │ ├── __init__.py
│ │ └── 0001_init.py # Файл с миграцией
│ └── env.py # Настройки для alembic
│
├─ conf/ # Файлы конфигурации для prod
│ ├── settings_local.example.py # Пример для создания settings_local.py
│ └── Dockerfile # Файл для prod
│
├── pytest.ini # Конфигурация для pytest
├── conftest.py # Настройки выполнения тестов
│
├── .gitignore # Какие игнорировать файлы и папки в git
├── .gitlab-ci.yml # Настройки CI pipeline
│
├── pyproject.toml # Настройки Poetry
│
├── Makefile # Переиспользуемые bash команды
│
├── README.md # Описание проекта
├── CHANGELOG.md # Изменения в проекте
├── version.toml # Версия проекта
│
├── alembic.ini # Конфигурации для alembic
│
├── DockerfileDev # Файл для создания dev контейнера с APP
├── docker-compose.yml # Используется для сборки dev окружения
│
├── admin_panel.py # Админ панель
│
└── main.py # Точка входа в приложение, где создается экземпляр FastAPI.
Connecting to FastAPI
File main.py
:
from fastapi import FastAPI
from fastapi_accelerator.pattern.pattern_fastapi import base_pattern
from app.core.config import BASE_DIR_PROJECT, DEBUG, SECRET_KEY
from fastapi_accelerator.timezone import moscow_tz
from app.core.db import DatabaseManager
from app.core.security import AuthJWT
import app.api.v1.router as RouterV1
app = FastAPI()
# Паттерн для проекта
base_pattern(
app,
routers=(RouterV1.router,),
timezone=moscow_tz,
cache_status=True,
debug=DEBUG,
base_dir=BASE_DIR_PROJECT,
database_manager=DatabaseManager,
secret_key=SECRET_KEY,
)
# Подключить аутентификацию по JWT
AuthJWT.mount_auth(app)
Main components
Base Pattern
Function base_pattern
adds a lot of useful features to app
including:
Filling
state
and other information atapp
.Permission
CORS
.Connecting routers with support
ViewSet
.Adding a method
healthcheck
.Middleware
to debug the execution time of API requests.Detailed output for
HTTP
exceptions.
DatabaseManager
DatabaseManager
– is a universal tool for working with RDBMS, providing both synchronous and asynchronous (the name begins with a
) methods. DatabaseManager
uses a singleton path, so it can be easily substituted in tests.
Example of use:
from app.core.config import DATABASE_URL, DEBUG, DEV_STATUS
from fastapi_accelerator.dbsession import MainDatabaseManager
DatabaseManager = MainDatabaseManager(DATABASE_URL, echo=DEBUG, DEV_STATUS=DEV_STATUS)
General characteristics
DEV_STATUS
– Development mode indicator. AtDEV_STATUS=False
blocks critical operations from being executed (create_all
,drop_all
,clear_all
). This is a safety measure for the production environment.
Synchronous components
database_url
– Address for connecting to a synchronous database.engine
– Mechanism of synchronous interaction with the database.session
– Synchronous session generator.Base
– Base class for data models.Functionality:
get_session
– DB session injector.get_session_transaction
– DB session injector with transaction support.create_all
– Initialization of all tables in the database.drop_all
– Deleting the entire database structure.clear_all
– Clearing table contents. Parameterexclude_tables_name
Allows you to exclude certain tables from the cleaning process.
Asynchronous components
adatabase_url
– Address for connecting to an asynchronous database.aengine
– Asynchronous mechanism for working with the database, including connection pooling.asession
– Asynchronous session generator.Functionality:
aget_session
– Asynchronous DB session injector.aget_session_transaction
– Asynchronous DB session injector with transaction support.
OrmAsync
This class optimizes asynchronous interaction with the database:
get
– Extraction of an object according to specified criteria.get_list
– Getting a set of objects on request. (With the possibility of deep selection)update
– Modification of objects according to request.delete
– Deleting objects according to specified parameters.get_item
– Extracting an object by primary key. (With the possibility of deep selection)create_item
– Creation of a new object. (With the possibility of cascading creation)update_item
– Updating an object by primary key. (With the possibility of cascading update)delete_item
– Deleting an object by primary key. (With the possibility of cascading deletion)
Deep selection/cascade operations are the ability to work with related data.
Activated by parameterdeep=True
Examples:
get_list, get_item – Return objects with all associated data, ready for use in Pydantic
create_item – Creates records in related tables
update_item – Updates data in related tables
delete_item – Deletes records from related tables
ViewSet
ViewSet allows you to quickly create CRUD operations for models. Here is an example of usage:
from fastapi_accelerator.viewset import AppOrm, FullViewSet
from fastapi import APIRouter, Depends, Query
from app.api.v1.schemas.timemeasurement import TaskExecution
from app.models.timemeasurement import TaskExecution as TaskExecutionDb
router = APIRouter(prefix="/api/v1")
class FileViewSet(FullViewSet):
"""
Представление для работы с файлами
"""
# Модель БД
db_model = TaskExecutionDb
# Модель Схемы
pydantic_model = TaskExecution
'''
# Кеширование
cache_class = redis_client
cache_ttl = timedelta(minutes=10)
# Пагинация
paginator_class = DefaultPaginator
# Включить поддержку вложенных схем pydantic
# это значит что будет происходить рекурсивное
# создание, обновление, удаление связанных записей
deep_schema = True
# Включить защиту через JWT
dependencies = [Depends(jwt_auth)]
# Вы можете также переопределять методы:
async def db_update(
self, item_id: str | int | UUID, item: type[BaseModel], aorm: OrmAsync
) -> object:
"""Переопределение метода db_update"""
return await super().db_update(item_id, item, aorm)
def list(self):
"""Переопределение метода list"""
@self.router.get(f"{self.prefix}", tags=self.tags)
async def get_list_items(
skip: int = Query(0),
limit: int = Query(100),
aorm: OrmAsync = Depends(AppOrm.aget_orm),
) -> List[self.pydantic_model]:
return await aorm.get_list(
self.db_model,
select(self.db_model).offset(skip).limit(limit),
deep=self.deep_schema,
)
return get_list_items
'''
router.views = [
FileViewSet().as_view(router, prefix="/file"),
]
JWT authentication
To secure API endpoints, we use JWT authentication:
from fastapi_accelerator.auth_jwt import BaseAuthJWT
class AuthJWT(BaseAuthJWT):
def check_auth(username: str, password: str) -> bool:
"""Проверка введенного логина и пароля."""
return username == "admin" and password == "admin"
AuthJWT.mount_auth(app)
Example of API method protection:
from fastapi_accelerator.auth_jwt import jwt_auth
@app.get("/check_protected", summary="Проверить аутентификацию по JWT")
async def protected_route(jwt: dict = Depends(jwt_auth)):
return {"message": "This is a protected route", "user": jwt}
Admin panel
For convenient data management, we have integrated Flask-Admin:
from flask import Flask
from app.core.config import ADMIN_PASSWORD, ADMIN_USERNAME, SECRET_KEY
from app.db.base import DatabaseManager
from app.models import File, User
from fastapi_accelerator.pattern_flask_admin import base_pattern
app = Flask(__name__)
admin = base_pattern(
app,
SECRET_KEY,
ADMIN_PASSWORD,
ADMIN_USERNAME,
# > Модели которые нужны в админ панели
models=[User, File],
database_manager=DatabaseManager,
)
if __name__ == "__main__":
app.run(
host="0.0.0.0",
port=8001,
debug=True,
)
Testing
One of the key features of our toolkit is a powerful system for writing and running tests. It includes:
Fixtures for working with a test database and API client.
Decorators for authentication and fixture application.
Context manager for tracking SQL queries.
Utilities for checking JSON responses.
Testing through classes.
Example of test function:
from typing import Callable, NamedTuple
from fastapi.testclient import TestClient
from app.fixture.items_v1 import export_fixture_file
from fastapi_accelerator.db.dbsession import MainDatabaseManager
from fastapi_accelerator.testutils import apply_fixture_db, client_auth_jwt, track_queries, check_response_json
# Аутентифицировать тестового клиента
@client_auth_jwt(username="test")
# Создать тестовые данных из функции с фикстурами
@apply_fixture_db(export_fixture_file)
def test_имя(
client: TestClient, # Тестовый клиент для API запросов
url_path_for: Callable, # Функция для получения url по имени функции обработчика
db_manager: MainDatabaseManager, # Менеджер тестовой БД
fixtures: NamedTuple, # Хранит созданные данные из фикстур
):
# Проверка количество выполняемых SQL команд
with track_queries(db_manager, expected_count=3):
# Запрос в API
response = client.get(url_path_for("ИмяФункции"))
# Проверка JSON API ответа
check_response_json(
response,
200,
{
"id": fixtures.Имя.id,
},
)
Example of class test:
from typing import Callable, NamedTuple
from fastapi.testclient import TestClient
from app.fixture.items_v1 import export_fixture_file
from fastapi_accelerator.db.dbsession import MainDatabaseManager
from fastapi_accelerator.testutils import apply_fixture_db
from fastapi_accelerator.testutils.fixture_auth import client_auth_jwt
from fastapi_accelerator.testutils.fixture_db.trace_sql import track_queries
from fastapi_accelerator.testutils.utils import BaseAuthJwtPytest, check_response_json
BASE_URL_V1 = "/api/v1/"
class TestИмя(BaseAuthJwtPytest):
# Создать тестовые данных из функции с фикстурами
@apply_fixture_db(export_fixture_file)
def setUp(self, fixtures: NamedTuple):
self.url = BASE_URL_V1 + "taskexecution"
self.fixtures = fixtures # Хранит созданные данные из фикстур
def test_имя(self, client: TestClient, db_manager: MainDatabaseManager):
# Проверка количество выполняемых SQL команд
with track_queries(db_manager, expected_count=3):
# Запрос в API
response = client.get(self.url)
# Проверка JSON API ответа
check_response_json(
response,
200,
{
"id": self.fixtures.Имя.id,
},
)
Comparison with existing solutions
Although there are several projects offering tools for developing and testing FastAPI applications, our solution stands out for its complexity and specialization:
FastAPI-Utils
: Provides development utilities, but is less focused on testing.FastAPI-SQLAlchemy
: Integrates FastAPI with SQLAlchemy, including some testing utilities.FastAPI-Toolkit
: Offers a set of tools, but is less specialized for testing tasks.freddie
– In the archive on GitHub, only viewsetfastapi_viewsets
– Viewset onlyFastAPIwee
– Less specialized in testing tasks.
Our solution is different in that:
More specific to the tasks of testing FastAPI applications.
Provides a wider range of tools for various aspects of testing.
Includes unique features such as decorator
@apply_fixture_db
and context managertrack_queries
.Offers a comprehensive approach covering various aspects of developing and testing FastAPI applications.
Conclusion
The presented toolkit significantly simplifies and accelerates development on FastAPI. It provides ready-made solutions for typical tasks, improves the project structure and facilitates testing. Using these tools will allow developers to focus on the business logic of the application, rather than on the technical details of implementation.
While there are other tools in the FastAPI ecosystem, our solution stands out for its completeness and specialization specifically for testing tasks. This makes it a valuable addition to the existing resources for FastAPI developers.
We continue to develop this toolkit and welcome feedback from the community. If you have ideas for improvement or find a bug, please create an issue in our GitHub repository.
Development plans
Ensure compatibility with the latest(previous) versions of FastAPI and related libraries
Significantly increase code coverage with tests
Optimize existing code to improve performance
Conduct load testing and optimize critical sections of code
Refactor using best practices and design patterns
Develop and add a similar option to work with
WebSocket
Improve the mechanism for executing background tasks (
background tasks
)Improve the implementation of periodic tasks such as those presented in
fastapi-utils
Create several detailed example projects demonstrating different use cases
Expand the documentation by adding more practical guides and application recommendations
Explore integration opportunities with popular tools in the FastAPI ecosystem