corp-app/TECHDOC/API.md

11 KiB
Raw Blame History

API и интеграция

🌐 Базовая информация

Базовый URL: https://corp.robotail.pro

API версия: v1

Протоколы:

  • REST API - https://corp.robotail.pro/api/v1/
  • WebSocket - wss://corp.robotail.pro/ws

🔐 Аутентификация

Получение токена

POST /api/auth/token/
Content-Type: application/json

{
  "email": "user@example.com",
  "password": "password"
}

Ответ:

{
  "access": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Обновление токена

POST /api/auth/token/refresh/
Content-Type: application/json

{
  "refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Ответ:

{
  "access": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Использование токена

Все защищенные endpoints требуют Bearer токен в заголовке:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

👥 REST API - Пользователи

Получить список всех сотрудников

GET /api/v1/employees/
Authorization: Bearer {access_token}

Ответ:

[
  {
    "id": 1,
    "username": "ivan_ivanov",
    "email": "ivan@company.com",
    "firstName": "Иван",
    "lastName": "Иванов",
    "department": "IT",
    "position": "Разработчик",
    "isOnline": true,
    "avatarUrl": null
  },
  {
    "id": 2,
    "username": "maria_petrova",
    "email": "maria@company.com",
    "firstName": "Мария",
    "lastName": "Петрова",
    "department": "HR",
    "position": "Менеджер",
    "isOnline": false,
    "avatarUrl": null
  }
]

Получить текущего пользователя

GET /api/v1/employees/me/
Authorization: Bearer {access_token}

Ответ:

{
  "id": 1,
  "username": "ivan_ivanov",
  "email": "ivan@company.com",
  "firstName": "Иван",
  "lastName": "Иванов",
  "department": "IT",
  "position": "Разработчик",
  "isOnline": true,
  "avatarUrl": null
}

Поиск пользователей

GET /api/v1/users/search/?q={query}
Authorization: Bearer {access_token}

Параметры:

  • q (string, required) - поисковый запрос (имя, отдел, должность)

Пример:

GET /api/v1/users/search/?q=Иван

Ответ:

[
  {
    "id": 1,
    "username": "ivan_ivanov",
    "firstName": "Иван",
    "lastName": "Иванов",
    "department": "IT",
    "position": "Разработчик",
    "isOnline": true
  }
]

Обновить статус пользователя

PUT /api/v1/users/status/
Authorization: Bearer {access_token}
Content-Type: application/json

{
  "isOnline": true
}

Ответ:

{
  "success": true,
  "message": "Статус обновлен"
}

💬 REST API - Сообщения

Получить все сообщения

GET /api/v1/messages/
Authorization: Bearer {access_token}

Ответ:

[
  {
    "id": 1,
    "senderId": 2,
    "senderName": "Мария Петрова",
    "receiverId": 1,
    "content": "Привет! Как дела?",
    "timestamp": "2026-01-12T10:30:00Z",
    "isRead": false
  }
]

Получить сообщения с конкретным пользователем

GET /api/v1/messages/?user_id={userId}
Authorization: Bearer {access_token}

Параметры:

  • user_id (int, required) - ID пользователя для фильтрации

Пример:

GET /api/v1/messages/?user_id=2

Ответ:

[
  {
    "id": 1,
    "senderId": 2,
    "senderName": "Мария Петрова",
    "receiverId": 1,
    "content": "Привет!",
    "timestamp": "2026-01-12T10:30:00Z",
    "isRead": true
  },
  {
    "id": 2,
    "senderId": 1,
    "senderName": "Иван Иванов",
    "receiverId": 2,
    "content": "Привет! Как дела?",
    "timestamp": "2026-01-12T10:31:00Z",
    "isRead": true
  }
]

Отправить сообщение (REST fallback)

POST /api/v1/messages/
Authorization: Bearer {access_token}
Content-Type: application/json

{
  "senderId": 1,
  "receiverId": 2,
  "content": "Текст сообщения"
}

Ответ:

{
  "id": 3,
  "senderId": 1,
  "senderName": "Иван Иванов",
  "receiverId": 2,
  "content": "Текст сообщения",
  "timestamp": "2026-01-12T10:35:00Z",
  "isRead": false
}

🔌 WebSocket API

Подключение

URL: wss://corp.robotail.pro/ws

Поддерживаемые варианты URL:

  • wss://corp.robotail.pro/ws (основной)
  • ws://corp.robotail.pro/ws (без SSL)
  • wss://corp.robotail.pro/ws/ (со слешем)
  • wss://corp.robotail.pro/api/v1/ws
  • ws://corp.robotail.pro/api/v1/ws

WebSocketService автоматически пробует разные варианты и подключается к первому работающему

Обязательный заголовок:

Authorization: Bearer {access_token}

Пример подключения (C#):

var ws = new ClientWebSocket();
ws.Options.SetRequestHeader("Authorization", $"Bearer {accessToken}");
await ws.ConnectAsync(new Uri("wss://corp.robotail.pro/ws"), CancellationToken.None);

Формат сообщений

Все WebSocket сообщения имеют единый формат:

{
  "type": "message_type",
  "data": {
    // данные специфичные для типа
  }
}

Типы сообщений

1. Отправка сообщения (Client → Server)

{
  "type": "message",
  "data": {
    "receiverId": 2,
    "content": "Текст сообщения"
  }
}

2. Получение сообщения (Server → Client)

{
  "type": "message",
  "data": {
    "id": 456,
    "senderId": 2,
    "senderName": "Мария Петрова",
    "receiverId": 1,
    "content": "Текст сообщения",
    "timestamp": "2026-01-12T10:30:00Z"
  }
}

3. Индикатор набора текста (Client → Server)

{
  "type": "typing",
  "data": {
    "recipientId": 2,
    "isTyping": true
  }
}

4. Индикатор набора текста (Server → Client)

{
  "type": "typing",
  "data": {
    "senderId": 2,
    "senderName": "Мария Петрова",
    "isTyping": true
  }
}

5. Обновление статуса пользователя (Server → Client)

{
  "type": "user_status",
  "data": {
    "userId": 2,
    "isOnline": true
  }
}

Обработка событий (C#)

// Подписка на события
ServiceProvider.WebSocketService.MessageReceived += OnMessageReceived;
ServiceProvider.WebSocketService.UserStatusChanged += OnUserStatusChanged;
ServiceProvider.WebSocketService.TypingIndicatorReceived += OnTypingIndicator;

// Обработчики
private void OnMessageReceived(object sender, Message message)
{
    // Обработка нового сообщения
}

private void OnUserStatusChanged(object sender, (int userId, bool isOnline) status)
{
    // Обновление статуса пользователя в UI
}

private void OnTypingIndicator(object sender, (int userId, bool isTyping) typing)
{
    // Показать/скрыть индикатор "печатает..."
}

🔄 Система управления токенами

Автоматическое обновление

ApiService автоматически управляет токенами:

  1. При получении 401/403 ошибки:

    • Пытается обновить access токен используя refresh токен
    • Повторяет оригинальный запрос с новым токеном
    • При неудаче перенаправляет на страницу входа
  2. При успешном обновлении:

    • Сохраняет новый access токен в SecureStorage
    • Обновляет HTTP заголовки
    • Возвращает результат оригинального запроса
  3. При неудаче обновления:

    • Очищает все токены
    • Очищает SecureStorage
    • Требует повторную аутентификацию

Хранение токенов

Токены хранятся в SecureStorage:

// Сохранение
await SecureStorage.SetAsync("access_token", accessToken);
await SecureStorage.SetAsync("refresh_token", refreshToken);

// Получение
var accessToken = await SecureStorage.GetAsync("access_token");
var refreshToken = await SecureStorage.GetAsync("refresh_token");

// Удаление
SecureStorage.Remove("access_token");
SecureStorage.Remove("refresh_token");

⚠️ Обработка ошибок

HTTP статус коды

  • 200 OK - успешный запрос
  • 201 Created - ресурс создан
  • 400 Bad Request - неверные параметры запроса
  • 401 Unauthorized - токен отсутствует или недействителен
  • 403 Forbidden - доступ запрещен
  • 404 Not Found - ресурс не найден
  • 500 Internal Server Error - ошибка сервера

Формат ошибок

{
  "error": "Описание ошибки",
  "detail": "Детальная информация",
  "code": "ERROR_CODE"
}

WebSocket коды закрытия

  • 1000 - нормальное закрытие
  • 1001 - сервер недоступен
  • 1006 - аномальное закрытие (например, потеря сети)
  • 1008 - нарушение политики (например, недействительный токен)

🔧 Конфигурация ApiService

var config = new ApiConfig
{
    BaseUrl = "https://corp.robotail.pro/api",
    TokenObtainPath = "/auth/token/",
    TokenRefreshPath = "/auth/token/refresh/",
    Timeout = 30,
    DefaultHeaders = new Dictionary<string, string>
    {
        { "Accept", "application/json" },
        { "Content-Type", "application/json" }
    }
};

var apiService = new ApiService(config);

📝 Примечания

Лимиты и ограничения

  • Максимальная длина сообщения: 4000 символов
  • Rate limiting: 100 запросов в минуту на пользователя
  • WebSocket idle timeout: 5 минут без активности

Рекомендации

  1. Приоритет WebSocket - используйте WebSocket для отправки сообщений, REST API только как fallback
  2. Переподключение - реализуйте автоматическое переподключение WebSocket при разрыве
  3. Кэширование - кэшируйте список пользователей для offline режима
  4. Optimistic UI - обновляйте UI сразу, не дожидаясь ответа сервера

Последнее обновление: 2026-01-12