Files
2026-09-22 09:07:31 +03:00

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 .