#Работа с файлами Диска

Сложность: beginner | Скоупы: disk | Стек: cURL / Node.js

#Что делаем

Управляем хранилищами, папками и файлами Bitrix24 Диска через Entity API. Получаем список хранилищ, просматриваем содержимое корневой папки (через обходной путь), создаём подпапки, получаем информацию о файлах. Примеры даны в cURL и Node.js.

Ограничение: загрузка файлов (disk.folder.uploadfile) пока не покрывается Entity API. Этот метод требует multipart-загрузку и не имеет entity-обёртки. Когда обёртка появится, рецепт будет обновлён.

#Доступные entity-эндпоинты

Entity Эндпоинт Операции
storages GET /v1/storages, GET /v1/storages/:id list, get (только чтение)
folders GET /v1/folders, GET /v1/folders/:id, POST /v1/folders, PATCH /v1/folders/:id, DELETE /v1/folders/:id list, get, create, update, delete
files GET /v1/files, GET /v1/files/:id, PATCH /v1/files/:id, DELETE /v1/files/:id list, get, update, delete (без create)

#Необходимо

  • API-ключ Вайбкод с правами disk
  • cURL (установлен в большинстве ОС) или Node.js 18+

#Полный код

Terminal
#!/bin/bash
# disk-operations.sh
# Операции с Bitrix24 Диском через Entity API

API_KEY="${VIBE_API_KEY}"
BASE_URL="${VIBE_BASE_URL}"

# ──────────────────────────────────────────
# 1. Получаем список хранилищ
#    GET /v1/storages
# ──────────────────────────────────────────
echo "Список хранилищ:"

curl -s -H "X-Api-Key: ${API_KEY}" \
  "${BASE_URL}/v1/storages" | python3 -m json.tool

# Ответ содержит поля: id, name, entityType, entityId, rootObjectId
# rootObjectId — это ID корневой папки хранилища (нужен дальше)

# ──────────────────────────────────────────
# 2. Получаем конкретное хранилище и его rootObjectId
#    GET /v1/storages/:id
# ──────────────────────────────────────────
STORAGE_ID=1

echo -e "\nХранилище #${STORAGE_ID}:"

curl -s -H "X-Api-Key: ${API_KEY}" \
  "${BASE_URL}/v1/storages/${STORAGE_ID}" | python3 -m json.tool

# ──────────────────────────────────────────
# 3. Содержимое корневой папки хранилища
#    Метода disk.storage.getchildren нет в Entity API.
#    Обходной путь: берём rootObjectId из хранилища
#    и запрашиваем GET /v1/folders?filter[parentId]=ROOT_OBJECT_ID
# ──────────────────────────────────────────
ROOT_FOLDER_ID=3  # rootObjectId из шага 2

echo -e "\nСодержимое корневой папки #${ROOT_FOLDER_ID}:"

curl -s -H "X-Api-Key: ${API_KEY}" \
  "${BASE_URL}/v1/folders?filter[parentId]=${ROOT_FOLDER_ID}" | python3 -m json.tool

# ──────────────────────────────────────────
# 4. Создаём подпапку
#    POST /v1/folders
#    parentId — ID родительской папки (rootObjectId или любая другая)
# ──────────────────────────────────────────
echo -e "\nСоздаём папку 'Документы клиентов':"

curl -s -X POST "${BASE_URL}/v1/folders" \
  -H "X-Api-Key: ${API_KEY}" \
  -H "Content-Type: application/json" \
  -d "{
    \"parentId\": ${ROOT_FOLDER_ID},
    \"name\": \"Документы клиентов\"
  }" | python3 -m json.tool

# ──────────────────────────────────────────
# 5. Список файлов
#    GET /v1/files
# ──────────────────────────────────────────
echo -e "\nФайлы на диске:"

curl -s -H "X-Api-Key: ${API_KEY}" \
  "${BASE_URL}/v1/files?limit=10" | python3 -m json.tool

# ──────────────────────────────────────────
# 6. Информация о конкретном файле
#    GET /v1/files/:id
# ──────────────────────────────────────────
FILE_ID=42

echo -e "\nФайл #${FILE_ID}:"

curl -s -H "X-Api-Key: ${API_KEY}" \
  "${BASE_URL}/v1/files/${FILE_ID}" | python3 -m json.tool

# ──────────────────────────────────────────
# 7. Пакетный запрос: получить хранилища + файлы за один вызов
#    POST /v1/batch (entity-формат)
# ──────────────────────────────────────────
echo -e "\nПакетный запрос — хранилища + файлы:"

curl -s -X POST "${BASE_URL}/v1/batch" \
  -H "X-Api-Key: ${API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "calls": [
      { "entity": "storages", "action": "list" },
      { "entity": "files", "action": "list", "params": { "limit": 5 } }
    ]
  }' | python3 -m json.tool
javascript
// disk-operations.js
// Node.js: работа с Диском через Entity API

const API_KEY = process.env.VIBE_API_KEY;
const BASE_URL = process.env.VIBE_BASE_URL;

const HEADERS = {
  'X-Api-Key': API_KEY,
  'Content-Type': 'application/json',
};

// Хелпер для GET-запросов
async function apiGet(path) {
  const response = await fetch(`${BASE_URL}${path}`, {
    headers: { 'X-Api-Key': API_KEY },
  });
  return response.json();
}

// Хелпер для POST-запросов
async function apiPost(path, body) {
  const response = await fetch(`${BASE_URL}${path}`, {
    method: 'POST',
    headers: HEADERS,
    body: JSON.stringify(body),
  });
  return response.json();
}

// 1. Список хранилищ (GET /v1/storages)
async function listStorages() {
  console.log('Хранилища:');
  const { data } = await apiGet('/v1/storages');

  for (const s of data) {
    console.log(`  [${s.id}] ${s.name} (${s.entityType}) — корневая папка: ${s.rootObjectId}`);
  }
  return data;
}

// 2. Содержимое корневой папки хранилища
//    Обходной путь: storage.rootObjectId → GET /v1/folders?filter[parentId]=...
async function listStorageRootContents(storageId) {
  console.log(`\nСодержимое хранилища #${storageId}:`);

  // Получаем хранилище, чтобы узнать rootObjectId
  const { data: storage } = await apiGet(`/v1/storages/${storageId}`);
  const rootFolderId = storage.rootObjectId;

  console.log(`  Корневая папка: #${rootFolderId}`);

  // Запрашиваем дочерние элементы корневой папки
  const { data: children } = await apiGet(
    `/v1/folders?filter[parentId]=${rootFolderId}`
  );

  for (const item of children) {
    console.log(`  [${item.id}] ${item.name}`);
  }
  return { rootFolderId, children };
}

// 3. Создание подпапки (POST /v1/folders)
async function createFolder(parentId, folderName) {
  console.log(`\nСоздаём папку "${folderName}" в папке #${parentId}...`);

  const { data } = await apiPost('/v1/folders', {
    parentId,
    name: folderName,
  });

  console.log(`  Папка создана: id=${data.id}`);
  return data;
}

// 4. Информация о файле (GET /v1/files/:id)
async function getFileInfo(fileId) {
  const { data } = await apiGet(`/v1/files/${fileId}`);
  console.log(`\nФайл #${fileId}: ${data.name} (${data.size} байт)`);
  return data;
}

// 5. Список файлов с фильтром (GET /v1/files)
async function listFiles(folderId) {
  console.log(`\nФайлы в папке #${folderId}:`);

  const { data } = await apiGet(
    `/v1/files?filter[folderId]=${folderId}`
  );

  for (const f of data) {
    console.log(`  [${f.id}] ${f.name} — ${f.size} байт`);
  }
  return data;
}

// 6. Пакетный запрос: хранилища + файлы за один вызов
//    POST /v1/batch (entity-формат)
async function batchDiskInfo() {
  console.log('\nПакетный запрос:');

  const result = await apiPost('/v1/batch', {
    calls: [
      { entity: 'storages', action: 'list' },
      { entity: 'files', action: 'list', params: { limit: 5 } },
    ],
  });

  const [storagesResult, filesResult] = result.data.results;

  console.log(`  Хранилищ: ${storagesResult.data?.length ?? 0}`);
  console.log(`  Файлов (первые 5): ${filesResult.data?.length ?? 0}`);
  return result.data;
}

// 7. Переименование файла (PATCH /v1/files/:id)
async function renameFile(fileId, newName) {
  console.log(`\nПереименование файла #${fileId} → "${newName}"...`);

  const response = await fetch(`${BASE_URL}/v1/files/${fileId}`, {
    method: 'PATCH',
    headers: HEADERS,
    body: JSON.stringify({ name: newName }),
  });

  const { data } = await response.json();
  console.log(`  Готово: ${data.name}`);
  return data;
}

// Демонстрация
async function demo() {
  // Список хранилищ
  const storages = await listStorages();
  if (storages.length === 0) {
    console.log('Хранилищ не найдено');
    return;
  }

  // Содержимое корневой папки первого хранилища
  const storageId = storages[0].id;
  const { rootFolderId } = await listStorageRootContents(storageId);

  // Создаём папку в корне хранилища
  const folder = await createFolder(rootFolderId, `Проект_${Date.now()}`);

  // Пакетный запрос
  await batchDiskInfo();

  console.log('\nВсе операции выполнены.');
  console.log('Загрузка файлов (disk.folder.uploadfile) пока не поддерживается через Entity API.');
}

demo().catch(console.error);

#Как это работает

  1. Список хранилищGET /v1/storages возвращает все доступные хранилища (личное, общее, хранилища отделов). Ключевое поле: rootObjectId — ID корневой папки.

  2. Содержимое хранилища — прямого эндпоинта disk.storage.getchildren в Entity API нет. Обходной путь:

    • Получаем хранилище: GET /v1/storages/:id
    • Извлекаем rootObjectId
    • Запрашиваем содержимое: GET /v1/folders?filter[parentId]=<rootObjectId>
  3. Создание папкиPOST /v1/folders с параметрами parentId и name. Можно создавать вложенные структуры, указывая ID родительской папки.

  4. Работа с файламиGET /v1/files (список), GET /v1/files/:id (информация), PATCH /v1/files/:id (переименование), DELETE /v1/files/:id (удаление).

  5. Пакетные запросыPOST /v1/batch принимает entity-формат: { entity: "storages", action: "list" }. До 50 вызовов за один запрос, одна единица rate-limit.

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

Операция Статус Комментарий
Загрузка файла (disk.folder.uploadfile) Недоступна Метод требует multipart-загрузку, entity-обёртки нет
disk.storage.getchildren Недоступна Используйте обходной путь через rootObjectId + GET /v1/folders
Создание файла (POST /v1/files) Недоступна Файлы создаются только через загрузку
Создание/изменение хранилища Недоступна Хранилища доступны только для чтения

#Что можно улучшить

  • Добавить рекурсивный обход вложенных папок для полной структуры диска
  • Автоматически создавать структуру папок по шаблону (например, для каждого клиента)
  • Комбинировать с CRM: при создании сделки автоматически создавать папку и добавлять комментарий в таймлайн с ссылкой на неё