Перейти к основному содержанию
Перейти к основному содержанию

Настройка конечных точек API для запросов

Возможность Query API Endpoints позволяет создавать конечные точки API непосредственно из любого сохранённого SQL-запроса в консоли ClickHouse Cloud. Вы сможете обращаться к конечным точкам API по HTTP для выполнения своих сохранённых запросов без необходимости подключаться к вашему сервису ClickHouse Cloud через нативный драйвер.

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

Прежде чем продолжить, убедитесь, что у вас есть:

  • Ключ API с соответствующими правами доступа
  • Роль Admin Console

Вы можете воспользоваться этим руководством, чтобы создать ключ API, если у вас его ещё нет.

Минимальные права доступа

Чтобы отправлять запрос к API-эндпоинту, ключу API необходима роль организации Member с доступом к сервису Query Endpoints. Роль базы данных настраивается при создании эндпоинта.

Создание сохранённого запроса

Если у вас уже есть сохранённый запрос, вы можете пропустить этот шаг.

Откройте новую вкладку запроса. В качестве примера мы будем использовать набор данных YouTube, который содержит примерно 4,5 миллиарда записей. Выполните шаги из раздела "Create table", чтобы создать таблицу в вашем Cloud-сервисе и вставить в неё данные.

Совет
Используйте LIMIT для ограничения количества строк

Учебный пример набора данных вставляет большой объём данных — 4,65 миллиарда строк, что может занять некоторое время. Для целей этого руководства мы рекомендуем использовать предложение LIMIT, чтобы вставить меньший объём данных, например 10 миллионов строк.

В качестве примера запроса мы вернём 10 лидеров по количеству загрузок по среднему числу просмотров на видео за год, переданный пользователем в параметре year.

WITH sum(view_count) AS view_sum,
  round(view_sum / num_uploads, 2) AS per_upload
SELECT
  uploader,
  count() AS num_uploads,
  formatReadableQuantity(view_sum) AS total_views,
  formatReadableQuantity(per_upload) AS views_per_video
FROM
  youtube
WHERE
-- highlight-next-line
  toYear(upload_date) = {year: UInt16}
GROUP BY uploader
ORDER BY per_upload desc
  LIMIT 10

Обратите внимание, что этот запрос содержит параметр (year), который выделен в приведённом выше фрагменте. Вы можете указывать параметры запроса, используя фигурные скобки { } вместе с типом параметра. Редактор запросов SQL Console автоматически обнаруживает выражения параметров запроса ClickHouse и предоставляет поле ввода для каждого параметра.

Быстро запустим этот запрос, чтобы убедиться, что он работает: укажите год 2010 в поле ввода переменных запроса справа от редактора SQL:

Проверка примерного запроса

Затем сохраните запрос:

Сохранить пример запроса

Дополнительную документацию по сохранённым запросам можно найти в разделе "Сохранение запроса".

Настройка API-эндпоинта для запроса

Эндпоинты Query API можно настраивать непосредственно из окна запроса, нажав кнопку Share и выбрав API Endpoint. Вам будет предложено указать, какие ключи API должны иметь доступ к этому эндпоинту:

Настройка эндпоинта запроса

После выбора ключа API вам будет предложено:

  • Выбрать роль базы данных, которая будет использоваться для выполнения запроса (Full access, Read only или Create a custom role)
  • Указать домены, разрешённые для CORS (cross-origin resource sharing)

После выбора этих параметров эндпоинт Query API будет автоматически создан.

Для отправки тестового запроса будет показана примерная команда curl:

Команда curl для эндпоинта

Команда curl, отображаемая в интерфейсе, приведена ниже для удобства:

curl -H "Content-Type: application/json" -s --user '<key_id>:<key_secret>' '<API-endpoint>?format=JSONEachRow&param_year=<value>'

Параметры Query API

Параметры в запросе можно задавать с помощью синтаксиса {parameter_name: type}. Эти параметры будут обнаружены автоматически, и пример тела запроса будет содержать объект queryVariables, через который вы можете передавать эти параметры.

Тестирование и мониторинг

После создания эндпоинта Query API вы можете проверить его работу, используя curl или любой другой HTTP-клиент:

curl-тест эндпоинта

После отправки первого запроса сразу справа от кнопки Share должна появиться новая кнопка. Нажав на неё, вы откроете боковую панель, содержащую данные мониторинга по этому запросу:

Мониторинг эндпоинта

Детали реализации

Этот эндпоинт выполняет запросы к вашим сохранённым эндпоинтам Query API. Он поддерживает несколько версий, гибкие форматы ответа, параметризованные запросы и, при необходимости, потоковые ответы (только версия 2).

Эндпоинт:

GET /query-endpoints/{queryEndpointId}/run
POST /query-endpoints/{queryEndpointId}/run

HTTP-методы

МетодСценарий использованияПараметры
GETПростые запросы с параметрамиПередавайте переменные запроса через параметры URL (?param_name=value)
POSTСложные запросы или когда используется тело запросаПередавайте переменные запроса в теле запроса (объект queryVariables)

Когда использовать GET:

  • Простые запросы без сложных вложенных данных
  • Параметры можно легко закодировать в URL
  • Преимущества кеширования благодаря семантике HTTP GET

Когда использовать POST:

  • Сложные переменные запроса (массивы, объекты, большие строки)
  • Когда для безопасности/конфиденциальности предпочтительно использовать тело запроса
  • Потоковая загрузка файлов или больших объёмов данных

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

Обязательно: Да
Метод: Базовая аутентификация (Basic Auth) с использованием ключа/секрета OpenAPI
Права доступа: Соответствующие права доступа для конечной точки запроса (endpoint)

Настройка запроса

Параметры URL

ПараметрОбязателенОписание
queryEndpointIdДаУникальный идентификатор endpoint'а запроса, который нужно выполнить

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

ПараметрОбязателенОписаниеПример
formatНетФормат ответа (поддерживаются все форматы ClickHouse)?format=JSONEachRow
param_:nameНетПеременные запроса, когда тело запроса передаётся как поток. Замените :name на имя вашей переменной?param_year=2024
request_timeoutНетТаймаут выполнения запроса в миллисекундах (по умолчанию: 30000)?request_timeout=60000
:clickhouse_settingНетЛюбая поддерживаемая настройка ClickHouse?max_threads=8

Заголовки

ЗаголовокОбязателенОписаниеЗначения
x-clickhouse-endpoint-versionНетУказывает версию эндпоинта1 или 2 (по умолчанию используется последняя сохранённая версия)
x-clickhouse-endpoint-upgradeНетЗапускает обновление версии эндпоинта (используется вместе с заголовком версии)1 для обновления

Тело запроса

Параметры

ПараметрТипОбязательныйОписание
queryVariablesobjectНетПеременные, которые будут использоваться в запросе
formatstringНетФормат ответа

Поддерживаемые форматы

ВерсияПоддерживаемые форматы
Версия 2Все форматы, поддерживаемые в ClickHouse
Версия 1 (ограниченная)TabSeparated
TabSeparatedWithNames
TabSeparatedWithNamesAndTypes
JSON
JSONEachRow
CSV
CSVWithNames
CSVWithNamesAndTypes

Ответы

Успешный ответ

Статус: 200 OK
Запрос был успешно выполнен.

Коды ошибок

Код состоянияОписание
400 Bad RequestЗапрос имеет неверный формат
401 UnauthorizedОтсутствует аутентификация или недостаточно прав
404 Not FoundУказанный endpoint запроса не найден

Рекомендации по обработке ошибок

  • Убедитесь, что в запрос включены корректные учетные данные для аутентификации
  • Проверьте корректность queryEndpointId и queryVariables перед отправкой
  • Реализуйте корректную обработку ошибок с понятными и информативными сообщениями

Обновление версий конечных точек

Чтобы выполнить обновление с версии 1 до версии 2:

  1. Добавьте заголовок x-clickhouse-endpoint-upgrade со значением 1
  2. Добавьте заголовок x-clickhouse-endpoint-version со значением 2

Это откроет доступ к возможностям версии 2, в том числе:

  • Поддержку всех форматов ClickHouse
  • Возможности потоковой передачи ответов
  • Повышенную производительность и функциональность

Примеры

Базовый запрос

SQL конечной точки API запросов:

SELECT database, name AS num_tables FROM system.tables LIMIT 3;

Версия 1

curl -X POST 'https://console-api.clickhouse.cloud/.api/query-endpoints/<endpoint id>/run' \
--user '<openApiKeyId:openApiKeySecret>' \
-H 'Content-Type: application/json' \
-d '{ "format": "JSONEachRow" }'

Версия 2

curl 'https://console-api.clickhouse.cloud/.api/query-endpoints/<endpoint id>/run?format=JSONEachRow' \
--user '<openApiKeyId:openApiKeySecret>' \
-H 'x-clickhouse-endpoint-version: 2'
{"database":"INFORMATION_SCHEMA","num_tables":"COLUMNS"}
{"database":"INFORMATION_SCHEMA","num_tables":"KEY_COLUMN_USAGE"}
{"database":"INFORMATION_SCHEMA","num_tables":"REFERENTIAL_CONSTRAINTS"}

Запрос с переменными запроса и версией 2 в формате JSONCompactEachRow

Query API Endpoint SQL:

SELECT name, database FROM system.tables WHERE match(name, {tableNameRegex: String}) AND database = {database: String};
curl 'https://console-api.clickhouse.cloud/.api/query-endpoints/<endpoint id>/run?format=JSONCompactEachRow&param_tableNameRegex=query.*&param_database=system' \
--user '<openApiKeyId:openApiKeySecret>' \
-H 'x-clickhouse-endpoint-version: 2'
["query_cache", "system"]
["query_log", "system"]
["query_views_log", "system"]

Запрос с массивом в переменных запроса, вставляющий данные в таблицу

SQL таблицы:

CREATE TABLE default.t_arr
(
    `arr` Array(Array(Array(UInt32)))
)
ENGINE = MergeTree
ORDER BY tuple()

SQL конечной точки API для запросов:

INSERT INTO default.t_arr VALUES ({arr: Array(Array(Array(UInt32)))});
curl -X POST 'https://console-api.clickhouse.cloud/.api/query-endpoints/<endpoint id>/run' \
--user '<openApiKeyId:openApiKeySecret>' \
-H 'Content-Type: application/json' \
-H 'x-clickhouse-endpoint-version: 2' \
-d '{
  "queryVariables": {
    "arr": [[[12, 13, 0, 1], [12]]]
  }
}'

Запрос с настройкой ClickHouse max_threads, равной 8

SQL для конечной точки Query API:

SELECT * FROM system.tables;
curl 'https://console-api.clickhouse.cloud/.api/query-endpoints/<endpoint id>/run?max_threads=8' \
--user '<openApiKeyId:openApiKeySecret>' \
-H 'x-clickhouse-endpoint-version: 2'

Выполнить запрос и разобрать ответ как поток`

SQL для конечной точки Query API:

SELECT name, database FROM system.tables;
async function fetchAndLogChunks(
  url: string,
  openApiKeyId: string,
  openApiKeySecret: string
) {
  const auth = Buffer.from(`${openApiKeyId}:${openApiKeySecret}`).toString(
    "base64"
  );

  const headers = {
    Authorization: `Basic ${auth}`,
    "x-clickhouse-endpoint-version": "2",
  };

  const response = await fetch(url, {
    headers,
    method: "POST",
    body: JSON.stringify({ format: "JSONEachRow" }),
  });

  if (!response.ok) {
    console.error(`HTTP error! Status: ${response.status}`);
    return;
  }

  const reader = response.body as unknown as Readable;
  reader.on("data", (chunk) => {
    console.log(chunk.toString());
  });

  reader.on("end", () => {
    console.log("Stream ended.");
  });

  reader.on("error", (err) => {
    console.error("Stream error:", err);
  });
}

const endpointUrl =
  "https://console-api.clickhouse.cloud/.api/query-endpoints/<endpoint id>/run?format=JSONEachRow";
const openApiKeyId = "<myOpenApiKeyId>";
const openApiKeySecret = "<myOpenApiKeySecret>";
// Пример использования
fetchAndLogChunks(endpointUrl, openApiKeyId, openApiKeySecret).catch((err) =>
  console.error(err)
);
> npx tsx index.ts
> {"name":"COLUMNS","database":"INFORMATION_SCHEMA"}
> {"name":"KEY_COLUMN_USAGE","database":"INFORMATION_SCHEMA"}
...
> Stream ended.

Вставка потока из файла в таблицу

Создайте файл ./samples/my_first_table_2024-07-11.csv со следующим содержимым:

"user_id","json","name"
"1","{""name"":""John"",""age"":30}","John"
"2","{""name"":""Jane"",""age"":25}","Jane"

SQL-запрос для создания таблицы:

create table default.my_first_table
(
    user_id String,
    json String,
    name String,
) ENGINE = MergeTree()
ORDER BY user_id;

SQL для конечной точки API запросов:

INSERT INTO default.my_first_table
cat ./samples/my_first_table_2024-07-11.csv | curl --user '<openApiKeyId:openApiKeySecret>' \
                                                   -X POST \
                                                   -H 'Content-Type: application/octet-stream' \
                                                   -H 'x-clickhouse-endpoint-version: 2' \
                                                   "https://console-api.clickhouse.cloud/.api/query-endpoints/<endpoint id>/run?format=CSV" \
                                                   --data-binary @-