FastAPI — частый вход в Python backend в CIS: типизированные эндпоинты, автодокументация, быстрый учебный контур. Это не «лучший фреймворк 2026» и не замена умению спроектировать схему данных. Вакансии проверяют сервис: валидация, БД, ошибки, тесты, деплой в Docker, честный README.
Ниже — карта до junior Python backend на FastAPI, 90-дневный проект, что писать в README и как стыковать поиск с вакансиями Python-разработчика. Общий Python: Python roadmap. Альтернатива, если в объявлениях Django: Django roadmap. Вход в роль: как стать Python-разработчиком и как стать backend-разработчиком.
Коротко:
- Один сервис, не обзор Starlette/Flask/FastAPI сразу.
- Pydantic-схемы, статус-коды, зависимость с сессией БД, миграции — ядро, не «hello world с swagger».
- Тесты на создание сущности и на 422/404. Без них swagger не нанимает.
- Docker Compose с Postgres. SQLite в портфолио backend допустим только с пометкой и пониманием отличий.
- Готовность — clone, up, открывается /docs, тесты зелёные, в README написано, чего нет.
Когда FastAPI, когда нет
Берите FastAPI, если в пяти вакансиях он есть или написано «Python API, async, pydantic». Если везде Django и админка — не насилуйте рынок своим предпочтением: либо маленький Django-проект, либо ищите FastAPI-роли. Оба в skills без двух репозиториев путают.
Async: уметь сказать, зачем await на I/O и почему sync-драйвер БД в async-хендлере — ловушка. Не обязаны писать высоконагруженный event loop в первый месяц.
Порядок внутри фреймворка
- Маршруты, модели запроса/ответа, валидация, понятные 422.
- Слой сервиса: не класть SQL в каждый хендлер без границы, даже в учебке обозначьте функции.
- SQLAlchemy 2 или другой ORM — один. Сессия, транзакция, зависимость FastAPI.
- Alembic: ревизия, upgrade, как накатить в Docker.
- Аутентификация учебная: простые токены или basic с огромным предупреждением в README, что это не прод-SSO.
- Логирование и корреляция запроса — хотя бы request id в логе.
- Тесты: httpx/TestClient, отдельная БД или транзакции.
Фоновые задачи, Kafka, WebSocket — только если в вакансиях. Иначе честно «нет». OpenAPI — бонус из коробки, не главная строка резюме.
Структура репозитория, которая читается за минуту: app/ (api, schemas, models, services), tests/, alembic/, docker-compose.yml, .env.example. Не один main.py на 800 строк. Не обязательно чистая гексагональная архитектура. Достаточно, чтобы хендлер не содержал SQL-простыню и чтобы тест импортировал приложение без ручного «поправь PYTHONPATH».
Идемпотентность на пальцах: повторный POST с тем же ключом не создаёт второй заказ — или создаёт, и вы это честно написали. Для junior достаточно одного явного поведения и теста. Валидация дат и валют: не принимайте строку «завтра» туда, где нужен ISO. Pydantic это закроет, если схема жёсткая; не держите все поля Optional «чтобы прошло».
Документация /docs полезна вам и рекрутеру, но не заменяет README. Если swagger открывается, а миграции не описаны, человек не дойдёт до /docs. Добавьте пример curl на создание заказа. Это пять строк и сильный сигнал.
Зависимости: pin в requirements или uv/poetry lock. Не «latest FastAPI» каждый день. Версия Python в README совпадает с образом. Если используете asyncpg — не смешивайте со sync psycopg без решения. Выберите один путь и держитесь 90 дней.
SQL как навык: SQL roadmap. Контейнеры: Docker roadmap.
README, который открывают на отборе
Пятнадцать-двадцать строк:
- что за сервис и какая сущность;
- как поднять: compose, миграции, пример запроса;
- стек и версии;
- что сделано вами;
- чего нет: оплаты, очереди, нормального auth;
- как прогнать тесты.
Без этого swagger по localhost, который не стартует у рекрутера, бесполезен. Как описывать проект в файле резюме: как описать проекты, каркас: резюме Python-разработчика.
Пример 1. 90-дневный сервис заказов
- Дни 1–15. Модель заказа, POST/GET, валидация пустой корзины, Postgres, Alembic init.
- Дни 16–40. Список с фильтром статуса, пагинация, 404, зависимость сессии, два теста на POST.
- Дни 41–65. Compose, переменные, health. Учебный токен или пометка «auth нет, не для прода». Лог с id запроса.
- Дни 66–90. README, DECISIONS.md с одним отказом (почему не положили бизнес-правило в хендлер). Резюме, отклики, письмо.
Откликаюсь на junior Python backend (FastAPI). Сервис заказов: Pydantic-схемы, PostgreSQL, Alembic, тесты на создание и 422, Docker Compose. Коммерческого стажа нет. На созвоне разберу зависимость сессии и миграции. Репозиторий: [ссылка]. Готов к тестовому 4–8 часов в FastAPI или близком API.
Черновик: генератор письма. Не оставляйте «динамичный FastAPI-разработчик» без ссылки.
Пример 2. Туториал vs работа
Было. Скопирован официальный tutorial, SQLite, один файл, нет тестов, в skills: FastAPI, Flask, Django, asyncio, Kafka. На тестовом — пустой репозиторий или тот же tutorial.
Стало. Свой домен, миграции, тесты, compose, в skills FastAPI + Postgres + Docker. Flask/Django нет, если нет кода.
Второй вариант проходит скрининг. Первый узнают. Навыки backend: навыки backend-разработчика. Проверка резюме: cv-review.
Созвон и тестовое
Спросят: чем Depends полезен, как отдать 409, чем sync-сессия опасна в async, зачем Pydantic. Отвечайте на своём заказе. Общие Python-вопросы: вопросы на собеседовании Python, каркас: interview-prep.
Тестовое часто: «сделайте CRUD и тесты». Не начинайте в ночь ставить Kafka. Жанр: тестовое задание на работу.
Сессия БД, async и типичные дыры
Depends с сессией: открыли, отдали в хендлер, закрыли. Не прячьте глобальный engine-синглтон «на скорую руку» без понимания пула. Если хендлер async, а драйвер синхронный, вы блокируете цикл — на созвоне это спрашивают почти всегда, когда в резюме FastAPI и async рядом. Честный учебный путь: sync-хендлеры плюс sync SQLAlchemy, либо async-стек целиком. Смесь без комментария в README — красный флаг.
Валидация: Pydantic режет плохой вход, но бизнес-правило «нельзя оплатить отменённый заказ» живёт в сервисе и даёт 409, не 422. Смешивать это — частая ошибка туториала. Тест должен ловить оба случая. 404 на чужой id, 401 на учебном токене, если вы его вообще ввели.
Миграции в Docker: команда upgrade в README или в entrypoint с оговоркой, что на проде так делают осторожнее. Пароль БД только из окружения. Это стыкуется с Docker roadmap и не требует Kubernetes.