Core API для Learnable: сервис авторизации и профилей пользователей на FastAPI.
Стек:
- FastAPI
- MongoDB
- Beanie
- Motor
- fastapi-users
- JWT access/refresh tokens
- Pydantic Settings
- uv
- Регистрация пользователей.
- Вход по email или username.
- JWT access token и refresh token.
- Обновление access token через refresh token.
- Получение и обновление текущего профиля.
- Публичный профиль пользователя по username.
- Создание, просмотр, обновление и удаление графов текущего пользователя.
- Админский список пользователей.
- Email verification и password reset роуты от
fastapi-users. - Health check.
- Python
3.13+ uv- Docker и Docker Compose для локальной MongoDB
Перейдите в папку API:
cd learnable-core-apiСкопируйте переменные окружения:
cp .env.example .envЗапустите MongoDB:
docker compose up -dУстановите зависимости:
uv syncЗапустите API:
uv run uvicorn app.main:app --reloadAPI будет доступен на:
http://localhost:8000- Swagger UI:
http://localhost:8000/docs - OpenAPI schema:
http://localhost:8000/openapi.json
Пример находится в .env.example.
| Переменная | Описание | Значение по умолчанию |
|---|---|---|
MONGODB_URL |
URL подключения к MongoDB | mongodb://localhost:27017 |
DATABASE_NAME |
Имя базы данных | learnable |
SECRET_KEY |
Секрет для JWT, reset password и verify email токенов | обязательна |
ACCESS_TOKEN_EXPIRE_MINUTES |
Время жизни access token в минутах | 30 |
REFRESH_TOKEN_EXPIRE_DAYS |
Время жизни refresh token в днях | 7 |
ALGORITHM |
JWT algorithm | HS256 |
SECRET_KEY в локальной разработке можно оставить тестовым, но для staging/production нужно использовать длинное случайное значение.
docker-compose.yml поднимает MongoDB 7:
docker compose up -dПроверить статус:
docker compose psОстановить MongoDB:
docker compose downОстановить и удалить локальные данные:
docker compose down -vlearnable-core-api/
├── app/
│ ├── main.py # FastAPI app, middleware, routers, lifespan
│ ├── config.py # Settings через pydantic-settings
│ ├── database.py # MongoDB client и Beanie init
│ ├── exceptions.py # Global exception handlers
│ └── modules/
│ ├── auth/
│ │ ├── router.py # Auth endpoints
│ │ ├── service.py # Login, refresh token, admin guard
│ │ ├── manager.py # fastapi-users UserManager
│ │ ├── backend.py # JWT backend
│ │ └── dependencies.py # Auth dependencies
│ ├── graphs/
│ │ ├── router.py # Graph CRUD endpoints
│ │ ├── service.py # Graph business logic and ownership checks
│ │ ├── repository.py # Beanie access layer
│ │ ├── schemas.py # Request/response schemas
│ │ └── models.py # Graph document
│ └── users/
│ ├── router.py # User and admin endpoints
│ ├── service.py # User business logic
│ ├── repository.py # Beanie access layer
│ ├── schemas.py # Request/response schemas
│ └── models.py # User document
├── docker-compose.yml
├── main.py # Local uvicorn entrypoint
├── pyproject.toml
├── requirements.txt
└── uv.lock
| Method | Path | Auth | Описание |
|---|---|---|---|
GET |
/health |
нет | Проверка, что сервис поднят |
| Method | Path | Auth | Описание |
|---|---|---|---|
POST |
/api/v1/auth/register |
нет | Регистрация пользователя |
POST |
/api/v1/auth/jwt/login |
нет | Вход и получение access/refresh token |
POST |
/api/v1/auth/jwt/refresh |
нет | Обновление пары токенов |
POST |
/api/v1/auth/jwt/logout |
нет | Logout endpoint, возвращает 204 |
POST |
/api/v1/auth/request-verify-token |
bearer | Запрос токена верификации email |
POST |
/api/v1/auth/verify |
нет | Верификация email |
POST |
/api/v1/auth/forgot-password |
нет | Запрос reset password токена |
POST |
/api/v1/auth/reset-password |
нет | Сброс пароля |
| Method | Path | Auth | Описание |
|---|---|---|---|
GET |
/api/v1/users/me |
bearer | Текущий профиль |
PATCH |
/api/v1/users/me |
bearer | Обновление текущего профиля |
GET |
/api/v1/users/{username} |
нет | Публичный профиль пользователя |
| Method | Path | Auth | Описание |
|---|---|---|---|
POST |
/api/v1/graphs |
bearer | Создать граф текущего пользователя |
GET |
/api/v1/graphs |
bearer | Список графов текущего пользователя |
GET |
/api/v1/graphs/{graph_id} |
bearer | Получить граф текущего пользователя |
PATCH |
/api/v1/graphs/{graph_id} |
bearer | Обновить граф текущего пользователя |
DELETE |
/api/v1/graphs/{graph_id} |
bearer | Удалить граф текущего пользователя |
Query параметры для списка графов:
skip: смещение, минимум0, по умолчанию0limit: размер страницы, от1до500, по умолчанию100
| Method | Path | Auth | Описание |
|---|---|---|---|
GET |
/api/v1/admin/users |
bearer, role=admin |
Список пользователей |
Query параметры:
skip: смещение, минимум0, по умолчанию0limit: размер страницы, от1до500, по умолчанию100
Ответы пользовательских эндпоинтов возвращают:
{
"id": "663000000000000000000000",
"email": "user@example.com",
"username": "john_doe",
"first_name": "John",
"last_name": "Doe",
"role": "user",
"is_active": true,
"is_verified": false,
"created_at": "2026-05-05T12:00:00.000Z"
}Username:
- приводится к lowercase;
- должен быть длиной от
3до30символов; - может содержать латинские буквы, цифры и
_; - уникален в MongoDB.
Пароль при регистрации должен быть минимум 8 символов и не должен содержать email пользователя.
curl -X POST http://localhost:8000/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "strong-password",
"username": "john_doe",
"first_name": "John",
"last_name": "Doe"
}'/api/v1/auth/jwt/login принимает application/x-www-form-urlencoded.
В поле username можно передать email или username.
curl -X POST http://localhost:8000/api/v1/auth/jwt/login \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=user@example.com&password=strong-password"Ответ:
{
"access_token": "<access-token>",
"refresh_token": "<refresh-token>",
"token_type": "bearer"
}curl -X POST http://localhost:8000/api/v1/auth/jwt/refresh \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "<refresh-token>"
}'curl http://localhost:8000/api/v1/users/me \
-H "Authorization: Bearer <access-token>"curl -X PATCH http://localhost:8000/api/v1/users/me \
-H "Authorization: Bearer <access-token>" \
-H "Content-Type: application/json" \
-d '{
"username": "john_updated",
"first_name": "John",
"last_name": "Updated"
}'curl http://localhost:8000/api/v1/users/john_updatedcurl -X POST http://localhost:8000/api/v1/graphs \
-H "Authorization: Bearer <access-token>" \
-H "Content-Type: application/json" \
-d '{
"name": "Math",
"description": "Course graph"
}'Ответ:
{
"id": "663000000000000000000001",
"owner_id": "663000000000000000000000",
"name": "Math",
"description": "Course graph",
"created_at": "2026-05-05T12:00:00.000Z",
"updated_at": "2026-05-05T12:00:00.000Z"
}curl "http://localhost:8000/api/v1/graphs?skip=0&limit=100" \
-H "Authorization: Bearer <access-token>"curl "http://localhost:8000/api/v1/admin/users?skip=0&limit=100" \
-H "Authorization: Bearer <admin-access-token>"У пользователя есть поле role:
useradmin
Админские эндпоинты используют bearer token активного пользователя и дополнительно проверяют role == "admin".
По умолчанию API принимает запросы с:
http://localhost:3000http://localhost:5173
Значение задается в app/config.py через cors_origins.
Запуск через uvicorn:
uv run uvicorn app.main:app --reloadЗапуск через entrypoint:
uv run python main.pyПроверка health endpoint:
curl http://localhost:8000/healthОжидаемый ответ:
{
"status": "ok"
}- Refresh tokens сейчас stateless: они подписываются
SECRET_KEYи не хранятся в базе. - Logout endpoint возвращает
204, но не инвалидирует уже выпущенные JWT. - Токены для email verification и password reset логируются в callback-методах
UserManager; отправка email пока не подключена. - В репозитории сейчас нет отдельного test suite.