update main server api docs
This commit is contained in:
+257
-80
@@ -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 <token>
|
||||
```
|
||||
|
||||
Токен выдаётся при регистрации или входе и действителен **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
|
||||
<!DOCTYPE html><html><body style="background-color: green"></body></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 }`
|
||||
|
||||
Reference in New Issue
Block a user