RESTful API сервер на Rust с JWT авторизацией для управления пользователями и постами.
- Rust + Tokio (асинхронный рантайм)
- Axum (веб-фреймворк)
- Diesel + diesel-async (ORM для PostgreSQL)
- jsonwebtoken (JWT авторизация)
- argon2_async (хэширование паролей)
- Validator (валидация данных)
- Rust (nightly или stable)
- PostgreSQL
git clone https://github.com/Aarende/posts-API
SERVER_IP=127.0.0.1:3000
DATABASE_URL=postgres://user:password@localhost:5432/posts_api
AUDIENCE=http://localhost:3000
JWT_ACCESS_SECRET=your-very-secret-access-key-minimum-32-bytes
JWT_REFRESH_SECRET=your-very-secret-refresh-key-minimum-32-bytes
diesel migration run
cargo run --release
API использует JWT токены двух типов:
- Access token (15 минут) — для доступа к защищённым эндпоинтам
- Refresh token (7 дней) — для получения новой пары токенов
Для доступа к защищённым эндпоинтам добавьте заголовок:
Authorization: Bearer <access_token>
Проверка работоспособности сервера.
Ответ:
pong!
Регистрация нового пользователя.
Тело запроса:
{
"nickname": "john_doe",
"password": "secure_password",
"about": "Описание пользователя (опционально)"
}
Успешный ответ (200):
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"user_id": 1,
"nickname": "john_doe"
}
Вход пользователя.
Тело запроса:
{
"nickname": "john_doe",
"password": "secure_password"
}
Успешный ответ (200):
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"user_id": 1,
"nickname": "john_doe"
}
Получение пользователя по ID.
Параметр пути: id — числовой идентификатор пользователя
Успешный ответ (200):
{
"id": 1,
"nickname": "john_doe",
"about": "Описание пользователя",
"created_at": "2024-01-01T00:00:00",
"last_updated": "2024-01-01T00:00:00"
}
Получение пользователя по nickname.
Параметр пути: nickname — строковый никнейм пользователя
Успешный ответ (200):
{
"id": 1,
"nickname": "john_doe",
"about": "Описание пользователя",
"created_at": "2024-01-01T00:00:00",
"last_updated": "2024-01-01T00:00:00"
}
Список пользователей с пагинацией и сортировкой.
Параметры запроса:
offset — смещение (по умолчанию 0) sort_by — сортировка: nickname_asc, nickname_desc, creation_time_asc, creation_time_desc
Пример: GET /users?offset=10&sort_by=nickname_asc
Успешный ответ (200):
[
{
"id": 1,
"nickname": "alice",
"about": null,
"created_at": "2024-01-01T00:00:00",
"last_updated": "2024-01-01T00:00:00"
},
{
"id": 2,
"nickname": "bob",
"about": "Hello",
"created_at": "2024-01-02T00:00:00",
"last_updated": "2024-01-02T00:00:00"
}
]
Получение поста по ID.
Параметр пути: id — числовой идентификатор поста
Успешный ответ (200):
{
"id": 1,
"title": "Заголовок поста",
"description": "Краткое описание",
"content": "Полное содержание поста...",
"author": "john_doe",
"created_at": "2024-01-01T00:00:00",
"last_updated": "2024-01-01T00:00:00"
}
Получение всех постов автора.
Параметры пути:
author — nickname автора
Параметры запроса:
offset — смещение (по умолчанию 0)
Пример: GET /posts/author/john_doe?offset=10
Успешный ответ (200):
[
{
"id": 1,
"title": "Первый пост",
"description": "Описание",
"content": "Содержание...",
"author": "john_doe",
"created_at": "2024-01-01T00:00:00",
"last_updated": "2024-01-01T00:00:00"
}
]
Список постов с пагинацией и сортировкой.
Параметры запроса:
-
offset — смещение (по умолчанию 0)
-
sort_by — сортировка: creation_time_asc, creation_time_desc
Пример: GET /posts?offset=10&sort_by=creation_time_desc
Успешный ответ (200):
[
{
"id": 1,
"title": "Новый пост",
"description": null,
"content": "Содержание...",
"author": "john_doe",
"created_at": "2024-01-01T00:00:00",
"last_updated": "2024-01-01T00:00:00"
}
]
Обновление своего профиля.
Заголовок: Authorization: Bearer <access_token>
Тело запроса:
{
"nickname": "new_nickname",
"about": "Новое описание"
}
Оба поля опциональны.
Успешный ответ (200):
{
"id": 1,
"nickname": "new_nickname",
"about": "Новое описание",
"created_at": "2024-01-01T00:00:00",
"last_updated": "2024-01-02T00:00:00"
}
Создание нового поста.
Заголовок: Authorization: Bearer <access_token>
Тело запроса:
{
"title": "Заголовок (3-50 символов)",
"description": "Описание (3-200 символов, опционально)",
"content": "Содержание (минимум 20 символов)"
}
Успешный ответ (200):
{
"id": 1,
"title": "Заголовок",
"description": "Описание",
"content": "Содержание...",
"author": "john_doe",
"created_at": "2024-01-01T00:00:00",
"last_updated": "2024-01-01T00:00:00"
}
Обновление своего поста.
Заголовок: Authorization: Bearer <access_token>
Тело запроса:
{
"id": 1,
"title": "Новый заголовок (опционально)",
"description": "Новое описание (опционально)",
"content": "Новое содержание (опционально)"
}
Успешный ответ (200):
{
"id": 1,
"title": "Новый заголовок",
"description": "Новое описание",
"content": "Новое содержание...",
"author": "john_doe",
"created_at": "2024-01-01T00:00:00",
"last_updated": "2024-01-02T00:00:00"
}
Выход из системы (отзыв refresh токена).
Заголовок: Authorization: Bearer <refresh_token>
Успешный ответ: 204 No Content
Обновление пары токенов (access + refresh).
Заголовок: Authorization: Bearer <refresh_token>
Успешный ответ (200):
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"user_id": 1,
"nickname": "john_doe"
}
200 OK — Успешный запрос
204 No Content — Успешный запрос (без содержимого)
400 Bad Request — Некорректные данные запроса
401 Unauthorized — Неавторизованный доступ
403 Forbidden — Доступ запрещён
404 Not Found — Ресурс не найден
409 Conflict — Конфликт (например, nickname уже занят)
500 Internal Server Error — Внутренняя ошибка сервера
src/
├── handlers/ # HTTP хендлеры
├── services/ # Бизнес-логика
├── repositories/ # Работа с БД
├── models/ # DTO и сущности
├── errors/ # Обработка ошибок
├── state/ # Состояние приложения
├── constants.rs # Константы
├── lib.rs # Основной модуль
├── main.rs # Точка входа
└── schema.rs # Схема БД (Diesel)
Локальная разработка:
cargo run