# Запросы к Discovery API

Платформа dbt | Starter, Enterprise, Enterprise+

Discovery API поддерживает разовые запросы и интеграции. Если вы только начинаете работать с этим API, ознакомьтесь с вводной информацией в разделе [О Discovery API](https://docs.getdbt.tech/docs/dbt-apis/discovery-api.md).

Информацию о квотах запросов и механизме ограничения их частоты см. в разделе [Ограничения частоты запросов API](https://docs.getdbt.tech/docs/dbt-apis/rate-limits.md).

Используйте Discovery API для оценки состояния конвейеров данных и состояния проекта как на протяжении нескольких запусков, так и в конкретный момент времени. dbt Labs предоставляет стандартный [GraphQL explorer](https://metadata.cloud.getdbt.com/graphql) для этого API, который позволяет выполнять запросы и просматривать схему. При этом вы также можете использовать любой другой GraphQL-клиент по своему выбору для обращения к API.

Поскольку GraphQL описывает данные, доступные в API, схема, отображаемая в GraphQL explorer, точно отражает граф и поля, доступные для запросов.

## Предварительные требования

* У вас должна быть [мультитенантная](https://docs.getdbt.tech/docs/platform/about-platform/tenancy.md#multi-tenant) или [однотенантная](https://docs.getdbt.tech/docs/platform/about-platform/tenancy.md#single-tenant) учетная запись dbt.
* Вы должны использовать [тарифный план Starter, Enterprise или Enterprise+](https://www.getdbt.com/pricing/).
* Ваши проекты должны использовать [каналы выпуска](https://docs.getdbt.tech/docs/dbt-versions/dbt-release-tracks.md) dbt или dbt версии 1.0 или более поздней. Инструкции по обновлению см. в разделе [Обновление версии dbt в Cloud](https://docs.getdbt.tech/docs/dbt-versions/upgrade-dbt-platform-version.md).

## Авторизация

В настоящее время авторизация запросов выполняется [с помощью сервисного токена](https://docs.getdbt.tech/docs/dbt-apis/service-tokens.md). Пользователи dbt с правами администратора могут создать сервисный токен с уровнем доступа Metadata Only, который разрешает выполнение определённого запроса к Discovery API.

Создав токен, вы можете использовать его в заголовке Authorization запросов к dbt Discovery API. Обязательно укажите префикс Token в заголовке Authorization, иначе запрос завершится с ошибкой `401 Unauthorized`. Обратите внимание, что в заголовке Authorization вместо `Token` можно использовать `Bearer`. Оба варианта синтаксиса эквивалентны.

## Доступ к Discovery API

1. Создайте [токен сервисного аккаунта](https://docs.getdbt.tech/docs/dbt-apis/service-tokens.md) для авторизации запросов. Пользователи dbt с правами администратора могут сгенерировать сервисный токен *Metadata Only*, который можно использовать для выполнения определённого запроса к Discovery API для авторизации запросов.

2. Определите URL API, который нужно использовать, из таблицы [Discovery API endpoints](#discovery-api-endpoints).

3. По вопросам, связанным с конкретными запросами, обратитесь к [документации схемы](https://docs.getdbt.tech/docs/dbt-apis/discovery-schema-job.md).

## Выполнение запросов с помощью HTTP-запросов

Вы можете выполнять запросы, отправляя `POST`-запросы к Discovery API, не забыв заменить:

* `YOUR_API_URL` на соответствующий [Discovery API endpoint](#discovery-api-endpoints) для вашего региона и тарифного плана.

* `YOUR_TOKEN` в заголовке Authorization на ваш реальный API-токен. Обязательно указывайте префикс Token.

* `QUERY_BODY` на GraphQL-запрос, например `{ "query": "<query text>", "variables": "<variables in json>" }`

* `VARIABLES` на словарь с переменными вашего GraphQL-запроса, например ID job или фильтр.

* `ENDPOINT` на endpoint, к которому вы обращаетесь, например environment.

  ```shell
  curl 'YOUR_API_URL' \
    -H 'authorization: Bearer YOUR_TOKEN' \
    -H 'content-type: application/json'
    -X POST
    --data QUERY_BODY
  ```

Пример на Python:

```python
response = requests.post(
    'YOUR_API_URL',
    headers={"authorization": "Bearer "+YOUR_TOKEN, "content-type": "application/json"},
    json={"query": QUERY_BODY, "variables": VARIABLES}
)

metadata = response.json()['data'][ENDPOINT]
```

Для каждого запроса потребуется ID окружения или задания. Вы можете получить этот ID из URL-адреса dbt или с помощью Admin API.

На этой странице приведено несколько наглядных примеров запросов. Дополнительные примеры см. в разделе [Сценарии использования и примеры для Discovery API](https://docs.getdbt.tech/docs/dbt-apis/discovery-use-cases-and-examples.md).

## Конечные точки Discovery API

Найдите свой эндпоинт Discovery API в разделе **Account settings** → **Access URLs** в dbt platform. Формат зависит от типа развертывания и региона:

| Deployment type      | Discovery API URL                                                   |
| -------------------- | ------------------------------------------------------------------- |
| Мультиарендная среда | `https://ACCOUNT_PREFIX.metadata.REGION.dbt.com/graphql`            |
| Одноарендная среда   | `https://ACCOUNT_PREFIX.metadata.ROUTING_SUBDOMAIN.dbt.com/graphql` |

* Замените следующие заполнители фактическими значениями. Дополнительную информацию о регионах и поддоменах см. в разделе [Доступ, регионы и IP-адреса](https://docs.getdbt.tech/docs/platform/about-platform/access-regions-ip-addresses.md):

  * `ACCOUNT_PREFIX` — идентификатор вашей учетной записи (указан в **Account settings** в разделе **Access URLs**)
  * `REGION` — регион вашего развертывания (например, `us1` для Северной Америки в AWS, `eu1` для EMEA, `jp1` для Японии, `au1` для APAC и т. д.)
  * `ROUTING_SUBDOMAIN` — поддомен маршрутизации вашей одноарендной среды (обычно это название вашей компании. Если вы не уверены, обратитесь к команде по работе с вашей учетной записью)
  * Например, если вы используете AWS в Северной Америке с префиксом учетной записи `abc123`, ваш URL Discovery API — `https://abc123.metadata.us1.dbt.com/graphql`.

## Разумное использование

Использование Discovery (GraphQL) API ограничено лимитами на частоту запросов и размер ответов, чтобы поддерживать производительность и стабильность платформы метаданных и предотвращать злоупотребления.

На эндпоинты уровня задания распространяются ограничения сложности запросов. Вложенные узлы (например, parents), код (например, rawCode) и столбцы каталога считаются наиболее сложными элементами. Слишком сложные запросы следует разбивать на отдельные запросы, включая в них только необходимые поля. Для большинства сценариев использования dbt Labs рекомендует вместо этого использовать эндпоинт окружения, чтобы получать актуальные описательные метаданные и метаданные результатов для проекта dbt.

## Ограничения хранения данных

Вы можете использовать Discovery API для запросов данных за последние два месяца. Например, если сегодня 1 апреля, вы сможете запрашивать данные начиная с 1 февраля.

## Выполнение запросов с помощью GraphQL explorer

Вы можете выполнять ad-hoc запросы напрямую в [GraphQL API explorer](https://metadata.cloud.getdbt.com/graphql) и использовать document explorer в левой части экрана, чтобы увидеть все доступные узлы и поля.

Информацию о настройке и авторизации GraphQL см. в [документации Apollo explorer](https://www.apollographql.com/docs/graphos/explorer/explorer).

1. Откройте [GraphQL API explorer](https://metadata.cloud.getdbt.com/graphql) и выберите поля, которые вы хотите запросить.

2. Внизу explorer выберите **Variables** и замените все поля со значением `null` на ваши уникальные значения.

3. [Аутентифицируйтесь](https://www.apollographql.com/docs/graphos/explorer/connecting-authenticating#authentication), используя Bearer auth с `YOUR_TOKEN`. Внизу explorer выберите **Headers** и нажмите **+New header**.

4. В выпадающем списке **header key** выберите **Authorization** и в поле **value** укажите ваш Bearer-токен. Не забудьте включить префикс Token. Заголовок должен иметь формат: `{"Authorization": "Bearer <YOUR_TOKEN>}`.

<br />

[![Введите ключ заголовка и значение токена аутентификации Bearer](/img/docs/dbt-platform/discovery-api/graphql_header.jpg?v=2 "Введите ключ заголовка и значение токена аутентификации Bearer")](#)Введите ключ заголовка и значение токена аутентификации Bearer

1. Запустите запрос, нажав синюю кнопку выполнения запроса в правом верхнем углу редактора **Operation** (справа от запроса). Справа в explorer вы должны увидеть успешный ответ на запрос.

[![Выполнение запросов с помощью обозревателя GraphQL Apollo Server](/img/docs/dbt-platform/discovery-api/graphql.jpg?v=2 "Выполнение запросов с помощью обозревателя GraphQL Apollo Server")](#)Выполнение запросов с помощью обозревателя GraphQL Apollo Server

### Фрагменты

Используйте нотацию [`... on`](https://www.apollographql.com/docs/react/data/fragments/) для выполнения запросов по lineage и получения результатов для конкретных типов узлов.

```graphql
query ($environmentId: BigInt!, $first: Int!) {
  environment(id: $environmentId) {
    applied {
      models(first: $first, filter: { uniqueIds: "MODEL.PROJECT.MODEL_NAME" }) {
        edges {
          node {
            name
            ancestors(types: [Model, Source, Seed, Snapshot]) {
              ... on ModelAppliedStateNestedNode {
                name
                resourceType
                materializedType
                executionInfo {
                  executeCompletedAt
                }
              }
              ... on SourceAppliedStateNestedNode {
                sourceName
                name
                resourceType
                freshness {
                  maxLoadedAt
                }
              }
              ... on SnapshotAppliedStateNestedNode {
                name
                resourceType
                executionInfo {
                  executeCompletedAt
                }
              }
              ... on SeedAppliedStateNestedNode {
                name
                resourceType
                executionInfo {
                  executeCompletedAt
                }
              }
            }
          }
        }
      }
    }
  }
}
```

### Пагинация

Запросы к большим наборам данных могут влиять на производительность нескольких функций в конвейере API. Пагинация снижает нагрузку, возвращая данные меньшими порциями — по одной странице за раз. Это позволяет получать определённую часть набора данных или весь набор по частям для повышения производительности. dbt использует пагинацию на основе курсора, которая упрощает получение страниц постоянно изменяющихся данных.

Используйте объект `PageInfo`, чтобы получить информацию о странице. Доступные поля:

* `startCursor` тип string — соответствует первому `node` в `edge`.
* `endCursor` тип string — соответствует последнему `node` в `edge`.
* `hasNextPage` тип boolean — указывает, есть ли дополнительные `nodes` после возвращённых результатов.

При выполнении запроса доступны следующие переменные соединения:

* `first` тип integer — возвращает первые n `nodes` на странице, максимум 500.
* `after` тип string — задаёт курсор, после которого нужно вернуть `nodes`. Рекомендуется указывать значение `after`, используя ID объекта из `endCursor` предыдущей страницы.

Ниже приведён пример, который возвращает первые 500 моделей (`first`) после указанного Object ID (`after`) в переменных. Объект `PageInfo` показывает, с какого Object ID начинается курсор, где он заканчивается и есть ли следующая страница.

[![Пример пагинации](/img/Paginate.png?v=2 "Пример пагинации")](#)Пример пагинации

Ниже приведён пример кода для объекта `PageInfo`:

```graphql
pageInfo {
  startCursor
  endCursor
  hasNextPage
}
totalCount # Total number of records across all pages
```

Описанный выше подход с `PageInfo` и `totalCount` применяется к эндпоинтам `environment`, которые возвращают результаты в виде соединения (connection) с `edges` и `nodes`.

[]()

#### Пагинация эндпоинтов на уровне задания

Эндпоинты списков на уровне задания также поддерживают пагинацию на основе курсора. Используйте этот подход при запросе ресурсов внутри объекта [`job`](https://docs.getdbt.tech/docs/dbt-apis/discovery-schema-job.md). Эти эндпоинты возвращают плоский список, а не соединение `edges`/`nodes`, поэтому объект `PageInfo` в них недоступен.

Следующие поля списков на уровне задания принимают аргументы `first` и `after`:

* `models`
* `sources`
* `seeds`
* `snapshots`
* `tests`
* `macros`
* `metrics`
* `exposures`

Передайте `first`, чтобы задать размер страницы (не более 100). Каждый возвращаемый элемент содержит поле `paginationCursor` — непрозрачное значение, индивидуальное для каждого элемента, которое нужно включить в выборку запроса. В следующем запросе передайте значение `paginationCursor` последнего элемента в качестве `after`, чтобы получить следующую страницу.

В отличие от запросов на уровне окружения, эти эндпоинты на уровне задания не возвращают объект `PageInfo` или поле `hasNextPage`. Последняя страница достигнута, если страница содержит меньше строк, чем задано в `first` (или меньше, чем размер страницы по умолчанию).

Рекомендуем всегда указывать `first`, чтобы ограничивать размер ответов. Ранее, если не указывать `first` и `after`, API возвращал все строки, соответствующие запросу. Для больших заданий рекомендуется явно передавать `first` и `after`, чтобы ваша интеграция не зависела от ответов без пагинации.

Предстоящее изменение запросов без пагинации

В одном из будущих обновлений запросы без `first` и `after` будут возвращать не более 100 строк. dbt Labs заранее уведомит о внедрении этого изменения.

Чтобы выполнить пример, используйте свой [эндпоинт Discovery API](#discovery-api-endpoints) и [сервисный токен с правами Metadata Only](#authorization). Получите `jobId` и необязательный `runId` из URL задания или запуска либо с помощью [Admin API](https://docs.getdbt.tech/docs/dbt-apis/admin-api.md). Если не указать `runId`, API использует последний запуск задания. Выполните запрос в [GraphQL explorer](#run-queries-with-the-graphql-explorer) или с помощью [HTTP-запросов](#run-queries-using-http-requests).

В приведённом ниже примере используется список `models` задания. Те же аргументы `first` и `after` работают и для других типов ресурсов, перечисленных выше. Пример сценария использования с большим количеством полей см. в разделе [Сценарии использования и примеры для Discovery API](https://docs.getdbt.tech/docs/dbt-apis/discovery-use-cases-and-examples.md).

```graphql
query JobModelsPage($jobId: BigInt!, $runId: BigInt, $first: Int!, $after: String) {
  job(id: $jobId, runId: $runId) {
    models(first: $first, after: $after) {
      uniqueId
      paginationCursor
    }
  }
}
```

Переменные для первой страницы:

```json
{
  "jobId": 12345,
  "runId": 67890,
  "first": 10,
  "after": null
}
```

Для следующей страницы задайте в `after` значение `paginationCursor` из *последней* строки предыдущей страницы. Курсор — это непрозрачная закодированная строка, а не `uniqueId`. Повторяйте запросы, пока страница не вернёт меньше строк, чем задано в `first` (или меньше, чем размер страницы по умолчанию).

```json
{
  "jobId": 12345,
  "runId": 67890,
  "first": 10,
  "after": "Y3Vyc29yOm1vZGVsLm15X3Byb2plY3QuZGltX2N1c3RvbWVycw=="
}
```

### Фильтры

Фильтрация помогает сузить результаты запроса к API. Если вы хотите запросить и получить только модели и тесты, выполнение которых завершается с ошибкой, или найти модели, выполнение которых занимает слишком много времени, вы можете получить сведения о выполнении, такие как [`executionTime`](https://docs.getdbt.tech/docs/dbt-apis/discovery-schema-job-models.md#fields), [`runElapsedTime`](https://docs.getdbt.tech/docs/dbt-apis/discovery-schema-job-models.md#fields) или [`status`](https://docs.getdbt.tech/docs/dbt-apis/discovery-schema-job-models.md#fields). Это помогает командам по работе с данными отслеживать производительность моделей, выявлять узкие места и оптимизировать конвейер обработки данных в целом.

Ниже приведён пример фильтрации результатов для моделей, которые успешно выполнились по значению `lastRunStatus`:

[![Пример фильтрации](/img/Filtering.png?v=2 "Пример фильтрации")](#)Пример фильтрации

Ниже приведён пример фильтрации моделей с ошибкой на последнем запуске и тестов, которые завершились с ошибкой:

```graphql
query ModelsAndTests($environmentId: BigInt!, $first: Int!) {
  environment(id: $environmentId) {
    applied {
      models(first: $first, filter: { lastRunStatus: error }) {
        edges {
          node {
            name
            executionInfo {
              lastRunId
            }
          }
        }
      }
      tests(first: $first, filter: { status: "fail" }) {
        edges {
          node {
            name
            executionInfo {
              lastRunId
            }
          }
        }
      }
    }
  }
}
```

## Связанные материалы

* [Сценарии использования и примеры для Discovery API](https://docs.getdbt.tech/docs/dbt-apis/discovery-use-cases-and-examples.md)
* [Схема](https://docs.getdbt.tech/docs/dbt-apis/discovery-schema-job.md)
