# Sea Battle — Main Server API Центральный сервер для браузерной онлайн-игры «Морской бой». Предоставляет REST API для регистрации, аутентификации и матчмейкинга. ## Базовый URL ``` http://localhost:3000/api ``` ## Аутентификация Все endpoints (кроме `/register` и `/login`) требуют JWT-токен в заголовке: ``` Authorization: Bearer ``` Токен выдаётся при регистрации или входе и действителен **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):** ```bash curl -X POST http://localhost:3000/api/register \ -H "Content-Type: application/json" \ -d '{ "user": { "nickname": "CaptainNemo", "password": "secret123", "password_confirmation": "secret123" } }' ``` **Пример запроса (с аватаром):** ```bash 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):** ```json { "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):** ```json { "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 | ✅ | Пароль | **Пример запроса:** ```bash curl -X POST http://localhost:3000/api/login \ -H "Content-Type: application/json" \ -d '{ "nickname": "CaptainNemo", "password": "secret123" }' ``` **Успешный ответ (200 OK):** ```json { "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):** ```json { "error": "Invalid nickname or password" } ``` --- ### Текущий пользователь Возвращает данные авторизованного пользователя. **URL:** `GET /api/me` **Auth:** требуется **Пример запроса:** ```bash curl -X GET http://localhost:3000/api/me \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..." ``` **Успешный ответ (200 OK):** ```json { "user": { "id": 1, "nickname": "CaptainNemo", "avatar_url": "http://localhost:3000/rails/active_storage/blobs/...", "created_at": "2026-09-21T10:00:00.000Z" } } ``` **Ошибка (401 Unauthorized):** ```json { "error": "Unauthorized" } ``` --- ### Выход Завершает сессию. JWT является stateless — клиент должен удалить токен. **URL:** `DELETE /api/logout` **Auth:** требуется **Пример запроса:** ```bash curl -X DELETE http://localhost:3000/api/logout \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..." ``` **Успешный ответ (200 OK):** ```json { "message": "Signed out successfully" } ``` --- ### Поиск случайного соперника (Матчмейкинг) Начинает поиск соперника. Работает в режиме **long-polling**: запрос зависает до 30 секунд, ожидая второго игрока. **URL:** `POST /api/matchmaking` **Auth:** требуется **Параметры:** нет **Пример запроса:** ```bash curl -X POST http://localhost:3000/api/matchmaking \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..." \ --max-time 35 ``` **Успешный ответ (200 OK)** — когда найден соперник: ```json { "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 секунд: ```json { "error": "No opponent found. Try again." } ``` **Ошибка (401 Unauthorized):** ```json { "error": "Unauthorized" } ``` **Примечание:** `game_token` содержит `match_id`, `player1_id`, `player2_id`, `game_server` и действителен **1 час**. --- ### Отмена поиска Убирает игрока из очереди матчмейкинга. **URL:** `DELETE /api/matchmaking` **Auth:** требуется **Пример запроса:** ```bash curl -X DELETE http://localhost:3000/api/matchmaking \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..." ``` **Успешный ответ (200 OK):** ```json { "message": "Matchmaking cancelled" } ``` --- ## Health Check Проверка доступности сервера. **URL:** `GET /up` **Auth:** не требуется **Успешный ответ (200 OK):** ```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: от регистрации до матча ```bash # 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 . ```