Возможность эндпоинты Query API позволяет создавать API-конечные точки напрямую из любого сохранённого SQL-запроса в консоли ClickHouse Cloud. Вы сможете обращаться к API-конечным точкам по HTTP, чтобы выполнять сохранённые запросы без необходимости подключаться к своему сервису ClickHouse Cloud через нативный драйвер.
Предварительные требования
Прежде чем продолжить, убедитесь, что у вас есть:
- API-ключ с соответствующими разрешениями
- роль Admin в консоли
Если у вас ещё нет API-ключа, воспользуйтесь этим руководством, чтобы создать API-ключ.
Создание сохраненного запроса
Если у вас уже есть сохраненный запрос, этот шаг можно пропустить.
Откройте новую вкладку запроса. Для примера мы будем использовать датасет YouTube, который содержит примерно 4,5 миллиарда записей. Следуйте инструкциям в разделе "Create table", чтобы создать таблицу в вашем сервисе Cloud и вставить в нее данные.
В качестве примера мы получим 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
toYear(upload_date) = {year: UInt16}
GROUP BY uploader
ORDER BY per_upload desc
LIMIT 10Обратите внимание, что этот запрос содержит параметр (year), который выделен в примере выше.
Параметры запроса можно задавать в формате { } вместе с типом параметра.
Редактор запросов в консоли SQL автоматически распознает выражения параметров в запросах к ClickHouse и показывает отдельное поле ввода для каждого параметра.
Давайте быстро выполним этот запрос, чтобы убедиться, что он работает: укажите год 2010 в поле переменных запроса справа в редакторе SQL:

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

Дополнительную информацию о сохраненных запросах можно найти в разделе "Saving a query".
Настройка эндпоинта Query API
Эндпоинты Query API можно настраивать прямо из представления запроса: нажмите кнопку Share и выберите API Endpoint.
Затем вам будет предложено указать, какие ключ API смогут обращаться к этому эндпоинту Query API:

После выбора ключа API вам будет предложено:
- Выбрать роль базы данных, которая будет использоваться для выполнения запроса (
Full access,Read onlyилиCreate a custom role) - Указать разрешенные домены CORS
После выбора этих параметров эндпоинт Query API будет создан автоматически.
Затем будет показан пример команды curl, чтобы вы могли отправить тестовый запрос:

Для удобства ниже приведена команда curl, отображаемая в интерфейсе:
curl -H "Content-Type: application/json" -s --user '<key_id>:<key_secret>' '<API-endpoint>?format=JSONEachRow¶m_year=<value>'Параметры Query API
Параметры в запросе можно задавать с помощью синтаксиса {parameter_name: type}. Эти параметры будут автоматически обнаружены, а пример тела запроса будет содержать объект queryVariables, через который их можно передавать.
Тестирование и мониторинг
После создания эндпоинта Query API вы можете проверить его работу с помощью curl или любого другого HTTP-клиента:

После отправки первого запроса сразу справа от кнопки Share должна появиться новая кнопка. При нажатии на нее откроется выдвижная панель с данными мониторинга по запросу:

Подробности реализации
Эта конечная точка выполняет запросы к вашим сохранённым эндпоинтам Query API. Она поддерживает несколько версий, гибкие форматы ответов, параметризованные запросы и опциональную потоковую передачу ответов (только в версии 2).
Конечная точка:
GET /query-endpoints/{queryEndpointId}/run
POST /query-endpoints/{queryEndpointId}/runHTTP-методы
| Метод | Сценарий использования | Параметры |
|---|---|---|
| GET | Простые запросы с параметрами | Передавайте переменные запроса через параметры URL (?param_name=value) |
| POST | Сложные запросы или случаи, когда используется тело запроса | Передавайте переменные запроса в теле запроса (объект queryVariables) |
Когда использовать GET:
- Простые запросы без сложных вложенных данных
- Параметры легко передаются в URL-кодировке
- Кэширование использует преимущества семантики HTTP GET
Когда использовать POST:
- Сложные переменные запроса (массивы, объекты, длинные строки)
- Когда тело запроса предпочтительнее с точки зрения безопасности и конфиденциальности
- Потоковая загрузка файлов или больших объёмов данных
Аутентификация
Требуется: Да Метод: Basic Auth с помощью OpenAPI Key/Secret Разрешения: Соответствующие разрешения для эндпоинта запроса
Настройка запроса
Параметры URL
| Параметр | Обязательно | Описание |
|---|---|---|
queryEndpointId |
Да | Уникальный идентификатор конечной точки запроса для выполнения |
Параметры запроса
| Параметр | Обязательно | Описание | Пример |
|---|---|---|---|
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 для обновления |
Тело запроса
Параметры
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
queryVariables |
объект | Нет | Переменные, используемые в запросе |
format |
строка | Нет | Формат ответа |
Поддерживаемые форматы
| Версия | Поддерживаемые форматы |
|---|---|
| Версия 2 | Все форматы, поддерживаемые ClickHouse |
| Версия 1 (ограниченная поддержка) | TabSeparated TabSeparatedWithNames TabSeparatedWithNamesAndTypes JSON JSONEachRow CSV CSVWithNames CSVWithNamesAndTypes |
Ответы
Успех
Статус: 200 OK
Запрос успешно выполнен.
Коды ошибок
| Код состояния | Описание |
|---|---|
400 Bad Request |
Запрос имеет неверный формат |
401 Unauthorized |
Отсутствует аутентификация или недостаточно разрешений |
404 Not Found |
Указанная конечная точка запроса не найдена |
Рекомендации по обработке ошибок
- Убедитесь, что запрос содержит действительные учетные данные для аутентификации
- Проверьте
queryEndpointIdиqueryVariablesперед отправкой - Реализуйте корректную обработку ошибок с понятными сообщениями
Обновление версий конечных точек
Чтобы перейти с версии 1 на версию 2:
- Добавьте заголовок
x-clickhouse-endpoint-upgradeсо значением1 - Добавьте заголовок
x-clickhouse-endpoint-versionсо значением2
Это дает доступ к возможностям версии 2, включая:
- Поддержку всех форматов ClickHouse
- Возможность потоковой передачи ответов
- Более высокую производительность и расширенную функциональность
Примеры
Простой запрос
SQL для эндпоинта Query 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" }'fetch(
"https://console-api.clickhouse.cloud/.api/query-endpoints/<endpoint id>/run",
{
method: "POST",
headers: {
Authorization: "Basic <base64_encoded_credentials>",
"Content-Type": "application/json",
},
body: JSON.stringify({
format: "JSONEachRow",
}),
}
)
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error("Error:", error));{
"data": {
"columns": [
{
"name": "database",
"type": "String"
},
{
"name": "num_tables",
"type": "String"
}
],
"rows": [
["INFORMATION_SCHEMA", "COLUMNS"],
["INFORMATION_SCHEMA", "KEY_COLUMN_USAGE"],
["INFORMATION_SCHEMA", "REFERENTIAL_CONSTRAINTS"]
]
}
}Версия 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"}curl -X POST 'https://console-api.clickhouse.cloud/.api/query-endpoints/<endpoint id>/run?format=JSONEachRow' \
--user '<openApiKeyId:openApiKeySecret>' \
-H 'Content-Type: application/json' \
-H 'x-clickhouse-endpoint-version: 2'fetch(
"https://console-api.clickhouse.cloud/.api/query-endpoints/<endpoint id>/run?format=JSONEachRow",
{
method: "POST",
headers: {
Authorization: "Basic <base64_encoded_credentials>",
"Content-Type": "application/json",
"x-clickhouse-endpoint-version": "2",
},
}
)
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error("Error:", error));{"database":"INFORMATION_SCHEMA","num_tables":"COLUMNS"}
{"database":"INFORMATION_SCHEMA","num_tables":"KEY_COLUMN_USAGE"}
{"database":"INFORMATION_SCHEMA","num_tables":"REFERENTIAL_CONSTRAINTS"}Запрос с переменными запроса и версией 2 в формате JSONCompactEachRow
SQL для эндпоинта Query API:
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¶m_tableNameRegex=query.*¶m_database=system' \
--user '<openApiKeyId:openApiKeySecret>' \
-H 'x-clickhouse-endpoint-version: 2'["query_cache", "system"]
["query_log", "system"]
["query_views_log", "system"]curl -X POST 'https://console-api.clickhouse.cloud/.api/query-endpoints/<endpoint id>/run?format=JSONCompactEachRow' \
--user '<openApiKeyId:openApiKeySecret>' \
-H 'Content-Type: application/json' \
-H 'x-clickhouse-endpoint-version: 2' \
-d '{ "queryVariables": { "tableNameRegex": "query.*", "database": "system" } }'fetch(
"https://console-api.clickhouse.cloud/.api/query-endpoints/<endpoint id>/run?format=JSONCompactEachRow",
{
method: "POST",
headers: {
Authorization: "Basic <base64_encoded_credentials>",
"Content-Type": "application/json",
"x-clickhouse-endpoint-version": "2",
},
body: JSON.stringify({
queryVariables: {
tableNameRegex: "query.*",
database: "system",
},
}),
}
)
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error("Error:", error));["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 для эндпоинта Query 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]]]
}
}'fetch(
"https://console-api.clickhouse.cloud/.api/query-endpoints/<endpoint id>/run",
{
method: "POST",
headers: {
Authorization: "Basic <base64_encoded_credentials>",
"Content-Type": "application/json",
"x-clickhouse-endpoint-version": "2",
},
body: JSON.stringify({
queryVariables: {
arr: [[[12, 13, 0, 1], [12]]],
},
}),
}
)
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error("Error:", error));OKЗапрос с настройкой 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'curl -X POST 'https://console-api.clickhouse.cloud/.api/query-endpoints/<endpoint id>/run?max_threads=8,' \
--user '<openApiKeyId:openApiKeySecret>' \
-H 'Content-Type: application/json' \
-H 'x-clickhouse-endpoint-version: 2' \fetch(
"https://console-api.clickhouse.cloud/.api/query-endpoints/<endpoint id>/run?max_threads=8",
{
method: "POST",
headers: {
Authorization: "Basic <base64_encoded_credentials>",
"Content-Type": "application/json",
"x-clickhouse-endpoint-version": "2",
},
}
)
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error("Error:", error));Запрос и разбор потокового ответа
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:
create table default.my_first_table
(
user_id String,
json String,
name String,
) ENGINE = MergeTree()
ORDER BY user_id;SQL-код для эндпоинта Query API:
INSERT INTO default.my_first_tablecat ./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 @-