8.4 KiB
Sea Battle — Main Server API
Центральный сервер для браузерной онлайн-игры «Морской бой». Предоставляет REST API для регистрации, аутентификации и матчмейкинга.
Базовый URL
http://localhost:3000/api
Аутентификация
Все endpoints (кроме /register и /login) требуют JWT-токен в заголовке:
Authorization: Bearer <token>
Токен выдаётся при регистрации или входе и действителен 7 дней.
Endpoints
Регистрация
Создаёт нового пользователя и возвращает токен.
URL: POST /api/register
Auth: не требуется
Content-Type: application/json или multipart/form-data (при загрузке аватара)
Параметры (JSON):
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
user.nickname |
string | ✅ | Уникальный никнейм (3–24 символа) |
user.password |
string | ✅ | Пароль (минимум 6 символов) |
user.password_confirmation |
string | ✅ | Подтверждение пароля |
user.avatar |
file | — | Аватар (PNG, JPEG, GIF, WebP) |
Пример запроса (JSON):
curl -X POST http://localhost:3000/api/register \
-H "Content-Type: application/json" \
-d '{
"user": {
"nickname": "CaptainNemo",
"password": "secret123",
"password_confirmation": "secret123"
}
}'
Пример запроса (с аватаром):
curl -X POST http://localhost:3000/api/register \
-F "user[nickname]=CaptainNemo" \
-F "user[password]=secret123" \
-F "user[password_confirmation]=secret123" \
-F "user[avatar]=@avatar.png"
Успешный ответ (201 Created):
{
"user": {
"id": 1,
"nickname": "CaptainNemo",
"avatar_url": "http://localhost:3000/rails/active_storage/blobs/...",
"created_at": "2026-09-21T10:00:00.000Z"
},
"token": "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjox..."
}
Ошибки (422 Unprocessable Entity):
{
"errors": [
"Nickname has already been taken",
"Password is too short (minimum is 6 characters)"
]
}
Вход
Аутентифицирует пользователя и возвращает токен.
URL: POST /api/login
Auth: не требуется
Content-Type: application/json
Параметры:
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
nickname |
string | ✅ | Никнейм |
password |
string | ✅ | Пароль |
Пример запроса:
curl -X POST http://localhost:3000/api/login \
-H "Content-Type: application/json" \
-d '{
"nickname": "CaptainNemo",
"password": "secret123"
}'
Успешный ответ (200 OK):
{
"user": {
"id": 1,
"nickname": "CaptainNemo",
"avatar_url": "http://localhost:3000/rails/active_storage/blobs/...",
"created_at": "2026-09-21T10:00:00.000Z"
},
"token": "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjox..."
}
Ошибка (401 Unauthorized):
{
"error": "Invalid nickname or password"
}
Текущий пользователь
Возвращает данные авторизованного пользователя.
URL: GET /api/me
Auth: требуется
Пример запроса:
curl -X GET http://localhost:3000/api/me \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..."
Успешный ответ (200 OK):
{
"user": {
"id": 1,
"nickname": "CaptainNemo",
"avatar_url": "http://localhost:3000/rails/active_storage/blobs/...",
"created_at": "2026-09-21T10:00:00.000Z"
}
}
Ошибка (401 Unauthorized):
{
"error": "Unauthorized"
}
Выход
Завершает сессию. JWT является stateless — клиент должен удалить токен.
URL: DELETE /api/logout
Auth: требуется
Пример запроса:
curl -X DELETE http://localhost:3000/api/logout \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..."
Успешный ответ (200 OK):
{
"message": "Signed out successfully"
}
Поиск случайного соперника (Матчмейкинг)
Начинает поиск соперника. Работает в режиме long-polling: запрос зависает до 30 секунд, ожидая второго игрока.
URL: POST /api/matchmaking
Auth: требуется
Параметры: нет
Пример запроса:
curl -X POST http://localhost:3000/api/matchmaking \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..." \
--max-time 35
Успешный ответ (200 OK) — когда найден соперник:
{
"match_id": "145575d6-3a4b-4c5d-9e6f-7a8b9c0d1e2f",
"game_token": "eyJhbGciOiJIUzI1NiJ9.eyJtYXRjaF9pZCI6IjE...",
"game_server": "ws://game-server.example.com:8080",
"players": [1, 2]
}
| Поле | Описание |
|---|---|
match_id |
Уникальный идентификатор матча (UUID) |
game_token |
JWT-токен для аутентификации на игровом сервере |
game_server |
WebSocket-адрес игрового сервера |
players |
ID обоих игроков [player1_id, player2_id] |
Таймаут (408 Request Timeout) — если соперник не найден за 30 секунд:
{
"error": "No opponent found. Try again."
}
Ошибка (401 Unauthorized):
{
"error": "Unauthorized"
}
Примечание: game_token содержит match_id, player1_id, player2_id, game_server и действителен 1 час.
Отмена поиска
Убирает игрока из очереди матчмейкинга.
URL: DELETE /api/matchmaking
Auth: требуется
Пример запроса:
curl -X DELETE http://localhost:3000/api/matchmaking \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..."
Успешный ответ (200 OK):
{
"message": "Matchmaking cancelled"
}
Health Check
Проверка доступности сервера.
URL: GET /up
Auth: не требуется
Успешный ответ (200 OK):
<!DOCTYPE html><html><body style="background-color: green"></body></html>
Коды ошибок
| Код | Описание |
|---|---|
200 |
Успешный запрос |
201 |
Ресурс создан (регистрация) |
401 |
Неавторизован (отсутствует/невалиден токен) |
408 |
Таймаут матчмейкинга (соперник не найден) |
422 |
Ошибка валидации |
500 |
Внутренняя ошибка сервера |
Переменные окружения
| Переменная | По умолчанию | Описание |
|---|---|---|
REDIS_URL |
redis://localhost:6379/0 |
Подключение к Redis |
GAME_SERVER_URL |
ws://game-server.example.com:8080 |
Адрес игрового сервера для матчмейкинга |
CORS_ORIGINS |
* |
Разрешённые origins для CORS (через запятую) |
SECRET_KEY_BASE |
из credentials.yml.enc |
Секретный ключ для JWT |
Пример workflow: от регистрации до матча
# 1. Регистрация
TOKEN=$(curl -s -X POST http://localhost:3000/api/register \
-H "Content-Type: application/json" \
-d '{"user":{"nickname":"Player1","password":"secret123","password_confirmation":"secret123"}}' \
| jq -r '.token')
# 2. Проверка профиля
curl -s http://localhost:3000/api/me \
-H "Authorization: Bearer $TOKEN"
# 3. Поиск матча (long-polling)
curl -s -X POST http://localhost:3000/api/matchmaking \
-H "Authorization: Bearer $TOKEN" \
--max-time 35 | jq .