## Получить строки таблицы

`GET /v1/infra/servers/:id/db/tables/:table/rows`

Возвращает строки таблицы или представления из SQLite-базы приложения постранично, с сортировкой по колонке и одним фильтром. Вместе со строками приходят ключи, по которым отдельную строку можно изменить или удалить.

Когда эндпоинт отвечает — см. [Когда база доступна](/docs/infra/database#когда-база-доступна).

## Параметры

| Параметр | Тип | Обяз. | По умолч. | Описание |
|----------|-----|:-----:|-----------|----------|
| `id` (path) | string | да | — | ID приложения с `kind` равным `GALAXY_APP`. Список: [`GET /v1/infra/servers`](/docs/infra/servers/list) |
| `table` (path) | string | да | — | Точное имя таблицы или представления, до 256 байт в UTF-8. Список: поле `data.tables[].name` в [`GET /db/schema`](/docs/infra/database/schema) |
| `file` (query) | string | нет | файл из `VIBE_DB_PATH`, иначе `app.db` | Путь к файлу базы относительно `/data`, до 1024 байт в UTF-8. Список файлов: поле `data.files[].file` в [`GET /db`](/docs/infra/database/info). Абсолютный путь, выход за пределы `/data` и символическая ссылка дают `400 APP_DB_INVALID_FILE` |
| `limit` (query) | number | нет | `100` | Число строк на странице, от `1` до `500` |
| `offset` (query) | number | нет | `0` | Сколько строк пропустить, от `0` до `1000000` |
| `sort` (query) | string | нет | — | Колонка для сортировки. Имя — из `data.tables[].columns[].name` в [`GET /db/schema`](/docs/infra/database/schema) |
| `order` (query) | string | нет | `asc` | Направление сортировки: `asc` или `desc` |
| `filterColumn` (query) | string | нет | — | Колонка, по которой фильтруются строки. Имя — из той же схемы, что и для `sort` |
| `filterOp` (query) | string | нет | — | Условие фильтра: `eq` — значение колонки равно `filterValue`, `contains` — значение колонки, приведённое к тексту, содержит `filterValue` как подстроку с учётом регистра. Символы `%` и `_` в `contains` ищутся как обычные символы, а не как шаблон |
| `filterValue` (query) | string | нет | — | Значение для сравнения, до 16 384 символов. Длину ограничивает и вся строка запроса: значение из 8 000 латинских символов проходит, из 12 000 — сервер отвечает `414` без JSON-тела. Пустая строка — отдельное значение, а не отсутствие значения |
| `filterValueIsNull` (query) | string | нет | — | `true` — отобрать строки, где в `filterColumn` записано SQL-значение `NULL`. Передаётся вместо `filterValue` и только с `filterOp=eq` |

Фильтр передаётся целиком или не передаётся вовсе: `filterColumn`, `filterOp` и одно из двух — `filterValue` или `filterValueIsNull=true`. Неполный фильтр, оба значения сразу, `filterValueIsNull=true` с `contains`, значение вне диапазона и любой параметр не из таблицы дают `400 VALIDATION_ERROR`. Имя колонки в `sort` или `filterColumn`, которого нет в таблице, даёт `404 APP_DB_TABLE_NOT_FOUND`.

**Пагинация.** За один вызов приходит не больше `limit` строк и не больше 1 МиБ JSON. Значение `data.truncated` равно `true`, когда за пределами страницы есть ещё строки или страница обрезана по размеру — тогда `data.rowCount` может оказаться меньше `limit`. Следующая страница запрашивается с `offset`, равным `data.offset + data.rowCount`.

**Порядок строк в таблице и в представлении.** В таблице строки сортируются по `sort`, затем по колонкам первичного ключа по возрастанию, затем по скрытому `rowid`, если он есть. Без `sort` порядок задаёт первичный ключ или `rowid`, поэтому страницы через `offset` не пересекаются и не теряют строки, пока данные не меняются. У представления такого добавочного порядка нет: страницы представления через `offset` могут повторять или пропускать строки.

## Примеры

### curl — личный ключ

```bash
curl "https://vibecode.bitrix24.tech/v1/infra/servers/7c2b1f08-3a4d-4e91-9b6c-2f5e8a1d0c33/db/tables/customers/rows?limit=2" \
  -H "X-Api-Key: YOUR_API_KEY"
```

### curl — OAuth-приложение

```bash
curl "https://vibecode.bitrix24.tech/v1/infra/servers/7c2b1f08-3a4d-4e91-9b6c-2f5e8a1d0c33/db/tables/customers/rows?limit=2" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN"
```

### JavaScript — личный ключ

```javascript
const appId = '7c2b1f08-3a4d-4e91-9b6c-2f5e8a1d0c33'
const res = await fetch(`https://vibecode.bitrix24.tech/v1/infra/servers/${appId}/db/tables/customers/rows?limit=2`, {
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
  },
})

const { success, data } = await res.json()
console.log(data.columns, data.rows)
```

### JavaScript — OAuth-приложение

```javascript
const appId = '7c2b1f08-3a4d-4e91-9b6c-2f5e8a1d0c33'
const res = await fetch(`https://vibecode.bitrix24.tech/v1/infra/servers/${appId}/db/tables/customers/rows?limit=2`, {
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
  },
})

const { success, data } = await res.json()
```

## Поля ответа

| Поле | Тип | Описание |
|------|-----|----------|
| `success` | boolean | Всегда `true` при успехе |
| `data.file` | string | Файл базы, из которого прочитаны строки, — путь относительно `/data` |
| `data.table` | string | Имя таблицы или представления из запроса |
| `data.columns` | array | Имена колонок в порядке их следования в таблице. Повторяющиеся имена остаются отдельными элементами |
| `data.rows` | array | Строки страницы. Каждая строка — массив значений в порядке `data.columns` |
| `data.rows[][]` | string, number, null, object | Значение ячейки. Объект приходит в трёх случаях: `{ "type": "blob", "base64": "..." }` — двоичные данные в base64, `{ "type": "integer", "value": "..." }` — целое число по модулю больше 9 007 199 254 740 991 в виде строки, `{ "type": "float", "value": "NaN" }` — нечисловое значение `NaN`, `Infinity` или `-Infinity` |
| `data.rowKeys` | array | Ключи строк, по одному на каждую строку `data.rows` в том же порядке |
| `data.rowKeys[]` | string, null | Непрозрачный ключ строки до 1024 символов — значение для `:key` в [`PATCH /db/tables/:table/rows/:key`](/docs/infra/database/rows-update) и [`DELETE /db/tables/:table/rows/:key`](/docs/infra/database/rows-delete). Ключ привязан к приложению, файлу и таблице, из которых прочитан. Берите его из ответа как есть, а не собирайте из значений колонок. `null` — строку нельзя изменить по ключу: это строка представления или виртуальной таблицы, у таблицы нет первичного ключа и скрытого `rowid`, в колонке первичного ключа этой строки записан `NULL` или двоичное значение, либо ключ длиннее 1024 символов |
| `data.rowCount` | number | Число строк на этой странице |
| `data.limit` | number | Значение `limit`, с которым выполнен запрос |
| `data.offset` | number | Значение `offset`, с которым выполнен запрос |
| `data.truncated` | boolean | `true` — за пределами страницы есть ещё строки или страница обрезана по размеру 1 МиБ |
| `data.durationMs` | number | Время чтения в миллисекундах |

## Пример ответа

Таблица `customers` с первичным ключом `id` и тремя строками, запрос с `limit=2`:

```json
{
  "success": true,
  "data": {
    "file": "app.db",
    "columns": [
      "id",
      "name",
      "email",
      "created_at"
    ],
    "rows": [
      [
        1,
        "Customer A",
        "a@example.com",
        "2026-10-20 08:12:46"
      ],
      [
        2,
        "Customer B",
        "b@example.com",
        "2026-10-20 08:12:46"
      ]
    ],
    "rowCount": 2,
    "truncated": true,
    "durationMs": 1.114,
    "rowKeys": [
      "eyJ2IjoxLCJhcHBJZCI6IjdjMmIxZjA4LTNhNGQtNGU5MS05YjZjLTJmNWU4YTFkMGMzMyIsImZpbGUiOiJhcHAuZGIiLCJ0YWJsZSI6ImN1c3RvbWVycyIsImtpbmQiOiJwayIsImNvbHVtbnMiOlsiaWQiXSwidmFsdWVzIjpbeyJ0eXBlIjoiaW50ZWdlciIsInZhbHVlIjoiMSJ9XX0",
      "eyJ2IjoxLCJhcHBJZCI6IjdjMmIxZjA4LTNhNGQtNGU5MS05YjZjLTJmNWU4YTFkMGMzMyIsImZpbGUiOiJhcHAuZGIiLCJ0YWJsZSI6ImN1c3RvbWVycyIsImtpbmQiOiJwayIsImNvbHVtbnMiOlsiaWQiXSwidmFsdWVzIjpbeyJ0eXBlIjoiaW50ZWdlciIsInZhbHVlIjoiMiJ9XX0"
    ],
    "table": "customers",
    "limit": 2,
    "offset": 0
  }
}
```

Представление `active_customers`, запрос без параметров — строки представления правке по ключу не подлежат, поэтому в `rowKeys` приходит `null`:

```json
{
  "success": true,
  "data": {
    "file": "app.db",
    "columns": [
      "id",
      "name"
    ],
    "rows": [
      [
        1,
        "Customer A"
      ],
      [
        2,
        "Customer B"
      ]
    ],
    "rowCount": 2,
    "truncated": false,
    "durationMs": 0.965,
    "rowKeys": [
      null,
      null
    ],
    "table": "active_customers",
    "limit": 100,
    "offset": 0
  }
}
```

## Пример ответа при ошибке

404 — таблицы с таким именем нет в базе:

```json
{
  "success": false,
  "error": {
    "code": "APP_DB_TABLE_NOT_FOUND",
    "message": "Table or column not found"
  }
}
```

## Ошибки

| HTTP | Код | Описание |
|------|-----|----------|
| 400 | `VALIDATION_ERROR` | Параметр вне допустимого диапазона, неизвестный параметр или неполный фильтр. Сообщение `Invalid database read parameters` |
| 400 | `VALIDATION_ERROR` | Имя таблицы в `:table` длиннее 256 байт. Сообщение `Invalid table name` |
| 400 | `APP_DB_INVALID_FILE` | Некорректный путь в `file`: абсолютный, с выходом за пределы `/data` или через символическую ссылку |
| 400 | `APP_DB_UNSUPPORTED_PLACEMENT` | Приложение размещено не в Галактике |
| 401 | `MISSING_API_KEY` | Не передан заголовок `X-Api-Key` |
| 401 | `INVALID_API_KEY` | Ключ не найден или недействителен |
| 402 | `BILLING_FROZEN` | Хост галактики спит, и его нельзя разбудить: счёт аккаунта заморожен |
| 403 | `INFRA_SCOPE_REQUIRED` | У ключа нет скоупа `vibe:infra` |
| 403 | `APP_DB_DISABLED` | Работа с базой приложения не включена для портала |
| 403 | `SERVER_WAKE_BLOCKED` | Хост галактики спит, и пробуждение для него запрещено |
| 404 | `NOT_FOUND` | Приложение не найдено, удалено или недоступно этому ключу |
| 404 | `APP_DB_NOT_FOUND` | У приложения нет тома `/data` или файла базы — приложение ещё не создало базу |
| 404 | `APP_DB_TABLE_NOT_FOUND` | В базе нет таблицы или представления `:table`, либо колонки из `sort` или `filterColumn` |
| 409 | `APP_DB_BUSY` | Хост занят другой операцией, ещё не проснулся или база занята записью приложения. Повторите после срока из заголовка `Retry-After` |
| 409 | `APP_DB_WAL_CLOSED` | Работающее приложение закрыло соединение с базой. Повтор без изменения приложения вернёт тот же отказ — см. [Когда база доступна](/docs/infra/database#когда-база-доступна) |
| 414 | — | Строка запроса длиннее предела сервера, ответ приходит HTML-страницей без JSON. Сократите `filterValue` |
| 422 | `APP_DB_QUERY_TIMEOUT` | Чтение не уложилось в отведённое время |
| 422 | `APP_DB_CORRUPT` | Файл базы повреждён. Восстановите базу из копии — [Восстановить базу из копии](/docs/infra/database/restore) |
| 429 | `RATE_LIMITED` | Превышен лимит запросов на чтение для портала — [Лимиты](/docs/infra/database#лимиты). Пауза — в заголовке `Retry-After` |
| 503 | `APP_DB_TOOL_UNAVAILABLE` | Хост не подготовлен к чтению базы или временно недоступен. Повторите после срока из заголовка `Retry-After`. Готовность хоста — [`GET /app-db/prepare`](/docs/infra/database/prepare-status) |
| 503 | `user_self_deletion_pending` | Владелец ключа удаляет свой аккаунт на этом портале |

Полный список общих ошибок API — [Ошибки](/docs/errors).

## Смотрите также

- [Получить схему базы](/docs/infra/database/schema)
- [Выполнить SQL-запрос на чтение](/docs/infra/database/query)
- [Добавить строку](/docs/infra/database/rows-create)
- [Изменить строку](/docs/infra/database/rows-update)
- [Удалить строку](/docs/infra/database/rows-delete)
- [Получить сведения о базе](/docs/infra/database/info)
- [База данных приложения](/docs/infra/database)
- [Ошибки](/docs/errors)
