Справочник REST API

DocPlatform предоставляет RESTful JSON API по адресу /api/v1/. Все endpoints требуют аутентификации, если не указано иное.

Базовый URL

http://localhost:3000/api/v1

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

Большинство endpoints требуют JWT access token в заголовке Authorization:

Authorization: Bearer eyJhbGciOiJSUzI1NiIs...

Получите токены через endpoints входа или OIDC.

Жизненный цикл токенов

Токен Срок жизни Назначение
Access token 15 минут Аутентификация API
Refresh token 30 дней Получение новых access token

Endpoints аутентификации

Регистрация

POST /api/v1/auth/register

Создание новой учетной записи. Первый пользователь становится Super Admin.

Запрос:

{
  "name": "Jane Smith",
  "email": "[email protected]",
  "password": "secure-password-here"
}

Ответ: 201 Created

{
  "user": {
    "id": "01HJK...",
    "name": "Jane Smith",
    "email": "[email protected]",
    "role": "superadmin"
  },
  "access_token": "eyJhbG...",
  "refresh_token": "eyJhbG...",
  "expires_in": 900
}

Вход

POST /api/v1/auth/login

Аутентификация с email и паролем.

Запрос:

{
  "email": "[email protected]",
  "password": "secure-password-here"
}

Ответ: 200 OK

{
  "access_token": "eyJhbG...",
  "refresh_token": "eyJhbG...",
  "expires_in": 900
}

Ошибки:

Код Описание
401 Неверные учетные данные
429 Слишком много попыток входа (ограничение частоты)

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

POST /api/v1/auth/refresh

Обмен refresh token на новый access token. Refresh token ротируется (старый инвалидируется).

Запрос:

{
  "refresh_token": "eyJhbG..."
}

Ответ: 200 OK

{
  "access_token": "eyJhbG...",
  "refresh_token": "eyJhbG...",
  "expires_in": 900
}

Запрос сброса пароля

POST /api/v1/auth/password-reset

Запрос токена сброса пароля. При настроенном SMTP отправляется email. Без SMTP токен логируется в stdout.

Запрос:

{
  "email": "[email protected]"
}

Ответ: 200 OK (всегда, независимо от существования email — предотвращает перебор)

Подтверждение сброса пароля

POST /api/v1/auth/password-reset/confirm

Установка нового пароля с использованием токена сброса.

Запрос:

{
  "token": "reset-token-here",
  "new_password": "new-secure-password"
}

Ответ: 200 OK


Endpoints контента

Все endpoints контента привязаны к workspace.

Список страниц

GET /api/v1/workspaces/{workspace_id}/pages

Возвращает все страницы, которые текущий пользователь имеет право просматривать.

Параметры запроса:

Параметр Тип Описание
parent_id string Фильтр по родительской странице (для древовидной навигации)
tag string Фильтр по тегу
published boolean Фильтр по статусу публикации
limit int Максимум результатов (по умолчанию: 100)
offset int Смещение пагинации

Ответ: 200 OK

{
  "pages": [
    {
      "id": "01HJK...",
      "title": "Getting Started",
      "slug": "getting-started",
      "description": "Install and configure DocPlatform.",
      "path": "getting-started.md",
      "tags": ["guide"],
      "published": true,
      "access": "public",
      "created_at": "2026-03-08T10:00:00Z",
      "updated_at": "2025-01-16T14:30:00Z",
      "author_id": "01HJK..."
    }
  ],
  "total": 42,
  "limit": 100,
  "offset": 0
}

Получение страницы

GET /api/v1/workspaces/{workspace_id}/pages/{page_id}

Ответ: 200 OK

{
  "id": "01HJK...",
  "title": "Getting Started",
  "slug": "getting-started",
  "description": "Install and configure DocPlatform.",
  "path": "getting-started.md",
  "content": "# Getting Started\n\nThis guide walks you through...",
  "content_hash": "sha256:abc123...",
  "tags": ["guide"],
  "published": true,
  "access": "public",
  "parent_id": null,
  "created_at": "2026-03-08T10:00:00Z",
  "updated_at": "2025-01-16T14:30:00Z",
  "author_id": "01HJK..."
}

Ошибки:

Код Описание
403 Недостаточно прав
404 Страница не найдена

Создание страницы

POST /api/v1/workspaces/{workspace_id}/pages

Запрос:

{
  "title": "New Page",
  "slug": "new-page",
  "content": "# New Page\n\nContent here...",
  "description": "Description for search and SEO.",
  "tags": ["guide"],
  "published": false,
  "parent_id": null
}

Ответ: 201 Created — возвращает полный объект страницы.

Обновление страницы

PUT /api/v1/workspaces/{workspace_id}/pages/{page_id}

Запрос:

{
  "title": "Updated Title",
  "content": "# Updated Title\n\nUpdated content...",
  "content_hash": "sha256:abc123..."
}

Поле content_hash обеспечивает оптимистичную конкурентность. Если хеш не совпадает с текущей версией, сервер возвращает 409 Conflict.

Ответ: 200 OK — возвращает обновленный объект страницы.

Ошибки:

Код Описание
409 Несовпадение хеша контента (обнаружено одновременное редактирование)

Удаление страницы

DELETE /api/v1/workspaces/{workspace_id}/pages/{page_id}

Ответ: 204 No Content


Endpoints workspaces

Список workspaces

GET /api/v1/workspaces

Возвращает workspaces, в которых текущий пользователь является участником.

Создание workspace

POST /api/v1/workspaces

Требует роль Super Admin.

Запрос:

{
  "name": "API Docs",
  "slug": "api-docs",
  "git_remote": "[email protected]:org/api-docs.git",
  "git_branch": "main"
}

Участники workspace

GET /api/v1/workspaces/{workspace_id}/members
POST /api/v1/workspaces/{workspace_id}/invitations
DELETE /api/v1/workspaces/{workspace_id}/members/{user_id}
PUT /api/v1/workspaces/{workspace_id}/members/{user_id}/role

Поиск

GET /api/v1/workspaces/{workspace_id}/search?q={query}

Параметры запроса:

Параметр Тип Описание
q string Поисковый запрос (обязательный)
tag string Фильтр по тегу
limit int Максимум результатов (по умолчанию: 20)

Ответ: 200 OK

{
  "results": [
    {
      "page_id": "01HJK...",
      "title": "Git Integration",
      "description": "Bidirectional git sync...",
      "path": "guides/git-integration.md",
      "score": 0.95,
      "highlights": [
        "...bidirectional <mark>git sync</mark> lets your team..."
      ]
    }
  ],
  "total": 5,
  "query": "git sync",
  "took_ms": 12
}

Результаты фильтруются по правам доступа — пользователи видят только те страницы, к которым имеют доступ.


Синхронизация git

Запуск синхронизации

POST /api/v1/workspaces/{workspace_id}/sync

Ручной запуск git pull + реконсиляция. Требует роль Admin.

Ответ: 200 OK

{
  "status": "completed",
  "changes": {
    "added": 2,
    "updated": 1,
    "deleted": 0
  }
}

Webhook endpoints

POST /api/v1/webhooks/github
POST /api/v1/webhooks/gitlab
POST /api/v1/webhooks/bitbucket

Эти endpoints принимают payload push-событий от хостинг-провайдеров git. Заголовок аутентификации не требуется — проверка выполняется с использованием общего секрета GIT_WEBHOOK_SECRET.


Состояние

Эти endpoints не требуют аутентификации.

GET /health    → 200 OK { "status": "ok" }
GET /ready     → 200 OK { "status": "ready", "db": "ok", "search": "ok" }

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

Все ответы с ошибками используют единый формат:

{
  "error": {
    "code": "CONFLICT",
    "message": "Content hash mismatch. The page was modified by another user.",
    "details": {
      "current_hash": "sha256:def456...",
      "provided_hash": "sha256:abc123..."
    }
  }
}

Общие коды ошибок

HTTP Код Описание
400 BAD_REQUEST Некорректное тело запроса или параметры
401 UNAUTHORIZED Отсутствует или недействительна аутентификация
403 FORBIDDEN Недостаточно прав
404 NOT_FOUND Ресурс не найден
409 CONFLICT Обнаружена одновременная модификация
429 RATE_LIMITED Слишком много запросов
500 INTERNAL_ERROR Ошибка сервера (проверьте логи)

Пагинация

Endpoints списков контента используют пагинацию на основе курсоров с ULID для стабильных результатов даже при добавлении или удалении контента.

Параметры запроса:

Параметр Тип По умолчанию Описание
cursor string ULID последнего элемента предыдущей страницы. Пропустите для первой страницы.
limit int 20 Количество результатов на страницу (максимум: 100)

Метаданные ответа:

{
  "data": [...],
  "next_cursor": "01HJK...",
  "has_more": true
}

Передайте next_cursor как параметр cursor в следующем запросе. Когда has_more равно false, вы достигли конца.


Загрузка ресурсов

POST /api/v1/workspaces/{workspace_id}/assets

Загрузка изображений и файлов в workspace. Ресурсы хранятся в директории assets/ workspace и коммитятся в git, если синхронизация включена.

Запрос: multipart/form-data с полем file.

Ограничения:

Ограничение Значение
Максимальный размер файла 10 МБ
Допустимые типы PNG, JPG, GIF, SVG, WebP, PDF

Ответ: 201 Created

{
  "path": "assets/screenshot-2025-01-15.png",
  "url": "/api/v1/workspaces/{workspace_id}/assets/screenshot-2025-01-15.png",
  "size": 245760,
  "content_type": "image/png"
}

Разрешение конфликтов

Список конфликтов

GET /api/v1/workspaces/{workspace_id}/conflicts

Ответ: 200 OK

{
  "workspace_id": "01HJK...",
  "sync_status": "conflict",
  "conflicts": [
    {
      "path": "guides/editor.md",
      "ours_hash": "abc123...",
      "theirs_hash": "def456...",
      "page_id": "01HJK...",
      "timestamp": "20250115T103045Z"
    }
  ]
}

Скачивание версии конфликта

GET /api/v1/conflicts/{page_id}/{timestamp}/{version}

Параметр version может быть ours (локальная) или theirs (удаленная).

Ответ: 200 OK с Content-Type: text/markdown — содержимое файла.

Разрешение конфликта

POST /api/v1/conflicts/{page_id}/{timestamp}/resolve

Удаляет артефакты конфликта после ручного разрешения.

Ответ: 200 OK

{
  "message": "Conflict resolved",
  "page_id": "01HJK..."
}

WebSocket

Получение ticket для подключения

POST /api/v1/auth/ws-ticket

WebSocket-подключения используют паттерн одноразового ticket, чтобы избежать раскрытия JWT-токенов в URL.

Ответ: 200 OK

{
  "ticket": "random-ticket-value",
  "expires_in": 30
}

Ticket действителен 30 секунд и может быть использован только один раз. Подключение через:

ws://localhost:3000/ws?ticket={ticket}

Серверные события

Тип события Payload Когда
page-created {workspace_id, path, actor} Создана новая страница
page-updated {workspace_id, path, actor} Страница изменена
page-deleted {workspace_id, path, actor} Страница удалена
presence-join {workspace_id, user_id} Пользователь подключился
presence-leave {workspace_id, user_id} Пользователь отключился (тайм-аут 90 с)
sync-status {workspace_id, status} Изменение статуса синхронизации git
conflict-detected {workspace_id, path} Обнаружен конфликт слияния git
bulk-sync {workspace_id, changed_count, paths[]} Синхронизировано несколько файлов (>20 файлов)

Клиентские сообщения

{"type": "subscribe", "workspace_id": "01HJK..."}
{"type": "unsubscribe", "workspace_id": "01HJK..."}

Заголовки безопасности

DocPlatform устанавливает следующие заголовки на все ответы:

Заголовок Значение
X-Content-Type-Options nosniff
X-Frame-Options DENY
Content-Security-Policy default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'
X-Request-ID ULID (уникальный для каждого запроса, включается в ответы об ошибках и логи)

Опубликованная документация дополнительно устанавливает:

Заголовок Значение
Cache-Control public, max-age=300
ETag Хеш контента отрендеренной страницы

Ограничение частоты запросов

Категория endpoints Community Edition
Операции чтения 100 / минуту на пользователя
Операции записи 20 / минуту на пользователя
Поиск 30 / минуту на пользователя
Аутентификация (login, register, reset) 5 / минуту на IP
Git webhooks 10 / минуту на workspace
Опубликованная документация (публичная) 1 000 / минуту на IP

Ответы с превышением лимита включают заголовки Retry-After (в секундах) и X-RateLimit-Reset (Unix timestamp).