Хватит тестировать на «кошках»! Разворачиваем циничный API на FastAPI за 5 минут для реальных AQA-задач

от автора

Привет, Хабр! Меня зовут Ваня (23 года), и я AQA-инженер. Как и многие из вас, я занимаюсь обучением будущих покорителей Postman и Pytest. И, как многие из вас, я столкнулся с проблемой: все существующие тестовые API — невыносимо скучные.

Todo-листы, интернет-магазины с товарами Item 1, Item 2, API для управления книгами… Серьезно? После пятого GET /todos начинаешь сомневаться не только в своей карьере, но и в смысле бытия. Данные в них стерильны, как операционная, а сценарии предсказуемы, как сюжет российского сериала.

Моим ученикам было скучно. Мне было скучно. Я понял, что нужен свой API. С блэкджеком и… ну, вы поняли. С API, который будет не просто функциональным, но и забавным. Который захочется «потыкать» просто ради того, чтобы увидеть очередной перл в ответе сервера.

Так родился «Cynical Circle API» — API для тех, кто понял жизнь и устал от ванильных примеров.

(Так выглядит наша интерактивная документация. Уже интригует, не правда ли?)

Концепция: тестовый бэкенд для циников

Идея проста: создать API, который имитирует небольшую социальную сеть для… уставших от всего людей. Вместо абстрактных «задач» и «продуктов» у нас есть две сущности:

  1. Пользователи (/users): Бедолаги, решившие зарегистрироваться в системе. О каждом можно сказать, что он «просто занимает место в базе данных».

  2. Посты (/posts): Тленные мысли, крики души и бессмысленные изречения, которые эти пользователи могут публиковать.

Ключевые особенности проекта:

  • Черный юмор: Все описания эндпоинтов, моделей и даже сообщения об ошибках пропитаны здоровой долей цинизма. 404 Not Found? Нет, «Пользователь не найден. Возможно, он обрёл свободу».

  • Zero-dependency (почти): Проект работает «in-memory». Никаких баз данных, Docker-контейнеров и прочих сложностей. Данные хранятся в обычном Python-списке и сбрасываются при перезапуске. Идеально для быстрых тестов.

  • Современный стек: Написан на FastAPI, что дает нам асинхронность, высокую скорость и, самое главное, автоматическую интерактивную документацию (Swagger UI и ReDoc). Для обучения — это киллер-фича.

  • Прозрачная структура: Код разбит на логические модули (роутеры, модели), что позволяет на его примере объяснять базовые принципы построения бэкенд-приложений.

Заглянем под капот

Давайте быстро пробежимся по архитектуре, чтобы вы понимали, насколько всё просто и прозрачно.

Структура проекта:

cynical_circle_api/ │ ├── app/ │   ├── main.py         # Точка входа, здесь живет экземпляр FastAPI │   ├── routers/        # Логика обработки запросов │   │   ├── users.py │   │   └── posts.py │   └── models/         # Модели данных Pydantic для валидации │       ├── user.py │       └── post.py │ └── requirements.txt      # Зависимости

Модели данных (Pydantic)

Вся валидация входящих и исходящих данных лежит на плечах Pydantic. Модели описаны предельно просто и с саркастичными комментариями.

app/models/user.py

from pydantic import BaseModel, Field from uuid import UUID  class UserBase(BaseModel):     username: str = Field(..., description="Имя пользователя, которое он забудет через неделю")     email: str = Field(..., description="Почта для спама и уведомлений, которые никто не читает")  class User(UserBase):     id: UUID     is_active: bool = Field(True, description="Активен ли пользователь или просто занимает место в базе данных")

Роутеры (Endpoints)

Логика каждого эндпоинта — это отдельная функция, обернутая в декоратор FastAPI. Вот, например, как выглядит создание пользователя. Обратите внимание на обработку ошибок.

app/routers/users.py

from fastapi import APIRouter, HTTPException, status # ... импорты  router = APIRouter()  # Наша "in-memory" база данных fake_users_db = []  @router.post("/", response_model=User, status_code=status.HTTP_201_CREATED, summary="Создать нового бедолагу") async def create_user(user_in: UserCreate):     """     Регистрирует нового пользователя в системе.     - **username**: Имя, которое скоро станет частью статистики.     - **email**: Адрес для получения рекламы казино.     - **password**: Секретная комбинация, известная вашему провайдеру.     """     if any(u.email == user_in.email for u in fake_users_db):         raise HTTPException(             status_code=status.HTTP_400_BAD_REQUEST,             detail="Эта почта уже занята кем-то более удачливым."         )     # ... логика создания пользователя

Каждая функция подробно документирована с помощью docstring. FastAPI автоматически подтягивает эти описания в Swagger, делая документацию живой и полезной.

Как запустить этот островок безысходности?

Всё до смешного просто. Понадобится Python 3.8+ и пара минут времени.

1. Создаем и активируем виртуальное окружение:

# Windows python -m venv venv && venv\Scripts\activate  # macOS/Linux python3 -m venv venv && source venv/bin/activate

2. Устанавливаем зависимости:

Проекту нужны всего три библиотеки: fastapi, uvicorn для запуска сервера и pydantic.

pip install fastapi uvicorn[standard] pydantic

3. Запускаем сервер:

Сохраните код из [репозитория](ссылка на ваш GitHub репозиторий) и выполните в терминале команду:

uvicorn app.main:app --reload

Сервер поднимется на http://127.0.0.1:8000.

4. Наслаждаемся!

Теперь можно открыть браузер и перейти по одному из адресов:

В Swagger можно не только посмотреть все эндпоинты, но и сразу же отправить на них запросы, посмотреть модели и коды ответов. Для новичков — это идеальная среда для знакомства с REST API.

Пример взаимодействия (для настоящих гуру терминала, ну или просто вставь в Postman)

Конечно, можно использовать и старый добрый cURL.

1. Создадим пользователя:

curl -X 'POST' \   'http://127.0.0.1:8000/users/' \   -H 'Content-Type: application/json' \   -d '{     "username": "Existential_Coder",     "email": "coder@example.com",     "password": "my_eternal_suffering_123"   }'

В ответ получим JSON с id нашего нового пользователя. Сохраним его.

2. Напишем пост от его имени:

curl -X 'POST' \   'http://127.0.0.1:8000/posts/?user_id=...ВАШ_ID_ПОЛЬЗОВАТЕЛЯ...' \   -H 'Content-Type: application/json' \   -d '{     "title": "Ода рефакторингу",     "content": "Вчера я 8 часов рефакторил код, который работал. Теперь он не работает, но зато красивый."   }'

3. Посмотрим на всеобщее уныние:

curl -X 'GET' 'http://127.0.0.1:8000/posts/'

UPD: Добавил документацию для этого API, в котором можно посмотреть всю актуальную реализацию проекта. Это так же будет полезно для наших маленьких любителей подёргать ручки.

Вместо заключения

«Cynical Circle API» — это не просто набор эндпоинтов. Это мой маленький протест против унылых и безжизненных учебных материалов. Это инструмент, который позволяет моим ученикам не просто писать автотесты, но и делать это с улыбкой. Когда твой тест падает, потому что API ответил 404 с сообщением «Удалять нечего. Мир и так пуст», это запоминается лучше, чем безликий {"detail": "Not Found"}.

Проект абсолютно открыт. Берите, пользуйтесь, дорабатывайте. Добавляйте новые эндпоинты (например, комментарии, полные пассивной агрессии), расширяйте модели, меняйте тексты на еще более абсурдные.

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

Весь код доступен на GitHub.

Спасибо за внимание и всем релизов без багов на проде!

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Какой тестовый стенд вы чаще всего используете для обучения?

100%Свой собственный «pet-project» (как в статье)1
0%Публичные API (типа JSONPlaceholder, Restful-booker)0
0%Готовые комплексные решения (например, reqres.in)0
0%Просто «мокаю» все ответы, мне не нужен живой стенд0
0%Другое (поделюсь в комментариях)0

Проголосовал 1 пользователь. Воздержавшихся нет.

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


Комментарии

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

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