From 4758ffeeb0cdd42d294821c67db78736a3162e7d Mon Sep 17 00:00:00 2001 From: Slavasil Date: Tue, 22 Sep 2026 09:07:31 +0300 Subject: [PATCH] update main server api docs --- main-server/API.md | 337 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 257 insertions(+), 80 deletions(-) diff --git a/main-server/API.md b/main-server/API.md index 4717109..7721f90 100644 --- a/main-server/API.md +++ b/main-server/API.md @@ -1,136 +1,303 @@ # Sea Battle — Main Server API -Базовый URL: `http://localhost:3000` +Центральный сервер для браузерной онлайн-игры «Морской бой». Предоставляет REST API для регистрации, аутентификации и матчмейкинга. -Все эндпоинты (кроме регистрации и входа) требуют заголовок: +## Базовый URL + +``` +http://localhost:3000/api +``` + +## Аутентификация + +Все endpoints (кроме `/register` и `/login`) требуют JWT-токен в заголовке: ``` Authorization: Bearer ``` +Токен выдаётся при регистрации или входе и действителен **7 дней**. + --- -## Аутентификация +## Endpoints -### POST /api/register +### Регистрация -Регистрация нового пользователя. +Создаёт нового пользователя и возвращает токен. -**Запрос** (`multipart/form-data` или `application/json`): +**URL:** `POST /api/register` -| Поле | Тип | Обязательное | Описание | -|------|-----|--------------|----------| -| `user[nickname]` | string | ✅ | 3–24 символа, уникальный | -| `user[password]` | string | ✅ | минимум 6 символов | -| `user[avatar]` | file | — | PNG, JPEG, GIF или WebP | +**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" + } + }' +``` + +**Пример запроса (с аватаром):** -**Пример (curl):** ```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`:** +**Успешный ответ (201 Created):** + ```json { "user": { "id": 1, "nickname": "CaptainNemo", "avatar_url": "http://localhost:3000/rails/active_storage/blobs/...", - "created_at": "2025-09-20T18:00:00.000Z" + "created_at": "2026-09-21T10:00:00.000Z" }, - "token": "eyJhbGciOiJIUzI1NiJ9..." + "token": "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjox..." } ``` -**Ошибки:** -- `422 Unprocessable Entity` — невалидные данные: - ```json - { "errors": ["Nickname has already been taken"] } - ``` - ```json - { "errors": ["Nickname is too short (minimum is 3 characters)"] } - ``` +**Ошибки (422 Unprocessable Entity):** + +```json +{ + "errors": [ + "Nickname has already been taken", + "Password is too short (minimum is 6 characters)" + ] +} +``` --- -### POST /api/login +### Вход -Вход по никнейму и паролю. +Аутентифицирует пользователя и возвращает токен. -**Запрос** (`application/json`): -```json -{ - "nickname": "CaptainNemo", - "password": "secret123" -} +**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`:** +**Успешный ответ (200 OK):** + ```json { "user": { "id": 1, "nickname": "CaptainNemo", "avatar_url": "http://localhost:3000/rails/active_storage/blobs/...", - "created_at": "2025-09-20T18:00:00.000Z" + "created_at": "2026-09-21T10:00:00.000Z" }, - "token": "eyJhbGciOiJIUzI1NiJ9..." + "token": "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjox..." } ``` -**Ошибки:** -- `401 Unauthorized`: - ```json - { "error": "Invalid nickname or password" } - ``` +**Ошибка (401 Unauthorized):** ---- - -### DELETE /api/logout - -Выход. JWT является stateless — клиент должен удалить токен на своей стороне. - -**Ответ `200 OK`:** ```json -{ "message": "Signed out successfully" } +{ + "error": "Invalid nickname or password" +} ``` --- -### GET /api/me +### Текущий пользователь -Информация о текущем аутентифицированном пользователе. +Возвращает данные авторизованного пользователя. + +**URL:** `GET /api/me` + +**Auth:** требуется + +**Пример запроса:** + +```bash +curl -X GET http://localhost:3000/api/me \ + -H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..." +``` + +**Успешный ответ (200 OK):** -**Ответ `200 OK`:** ```json { "user": { "id": 1, "nickname": "CaptainNemo", "avatar_url": "http://localhost:3000/rails/active_storage/blobs/...", - "created_at": "2025-09-20T18:00:00.000Z" + "created_at": "2026-09-21T10:00:00.000Z" } } ``` -**Ошибки:** -- `401 Unauthorized`: - ```json - { "error": "Unauthorized" } - ``` +**Ошибка (401 Unauthorized):** + +```json +{ + "error": "Unauthorized" +} +``` --- -## Системные эндпоинты +### Выход -### GET /up +Завершает сессию. JWT является stateless — клиент должен удалить токен. -Health check для мониторинга и load balancers. +**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):** -**Ответ `200 OK`:** ```html ``` @@ -141,31 +308,41 @@ Health check для мониторинга и load balancers. | Код | Описание | |-----|----------| -| `200` | Успех | -| `201` | Ресурс создан | -| `401` | Не авторизован (отсутствует/невалиден токен, неверный пароль) | +| `200` | Успешный запрос | +| `201` | Ресурс создан (регистрация) | +| `401` | Неавторизован (отсутствует/невалиден токен) | +| `408` | Таймаут матчмейкинга (соперник не найден) | | `422` | Ошибка валидации | +| `500` | Внутренняя ошибка сервера | -## Валидации +--- -| Поле | Правила | -|------|---------| -| `nickname` | 3–24 символа, уникальный (регистронезависимо) | -| `password` | минимум 6 символов | -| `avatar` | PNG, JPEG, GIF, WebP; опциональный | +## Переменные окружения -## CORS +| Переменная | По умолчанию | Описание | +|------------|--------------|----------| +| `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 | -Настроен через `config/initializers/cors.rb`. По умолчанию разрешены все origins (`*`). +--- + +## Пример workflow: от регистрации до матча -Для production задайте переменную окружения: ```bash -CORS_ORIGINS=https://your-frontend.com,https://www.your-frontend.com +# 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 . ``` - -## JWT - -- Алгоритм: `HS256` -- Срок жизни: **7 дней** -- Секретный ключ: `Rails.application.secret_key_base` -- Payload: `{ "user_id": 1, "exp": 1234567890 }`