INTEGRITY Документация

Создайте бессерверный, глобально распределённый API временных рядов с Timescale

В этом руководстве вы научитесь создавать на Workers API, который будет принимать и запрашивать временные ряды данных, хранящиеся в Timescale ↗ (они делают PostgreSQL быстрее в облаке).

Вы создадите и развернете функцию Worker, которая предоставляет API маршруты для приёма данных, и будете использовать Hyperdrive ↗ чтобы проксировать подключение к вашей базе данных на границе сети и поддерживать пул соединений, чтобы не создавать новое подключение к базе данных при каждом запросе.

Вы узнаете, как:

Подробнее о Timescale можно узнать в их документация ↗.


1. Создайте проект Worker

Выполните следующую команду, чтобы создать проект Worker из командной строки:

npm create cloudflare@latest -- timescale-api

Для настройки выберите следующие параметры:

Запишите URL, по которому было развёрнуто ваше приложение. Он понадобится вам при настройке вебхука GitHub.

Перейдите в каталог, который вы только что создали для своего проекта Worker:

cd timescale-api

2. Подготовка Timescale Service

Если вы создаете новый сервис, перейдите в Timescale Console ↗ и выполните следующие действия:

  1. Выберите Create Service выбрав чёрный значок плюс в правом верхнем углу.
  2. Выберите Временные ряды в качестве типа службы.
  3. Выберите нужный регион и размер инстанса. Для этого руководства будет достаточно 1 CPU.
  4. Задайте имя сервиса, чтобы заменить автоматически сгенерированное.
  5. Выберите Create Service.
  6. Справа разверните Информация о подключении диалоговом окне и скопируйте URL службы.
  7. Скопируйте отображаемый пароль. Повторно получить его будет уже нельзя.
  8. Выберите Я сохранил пароль, перейти к обзору сервиса.

Если вы используете ранее созданный сервис, сведения о подключении к нему можно найти в Timescale Console ↗:

  1. Выберите сервис (базу данных), к которому должен подключаться Hyperdrive.
  2. Развернуть Информация о подключении.
  3. Скопируйте URL службы. Service URL представляет собой строку подключения, которую использует Hyperdrive для соединения. Она включает имя хоста базы данных, номер порта и имя базы данных.

Вставьте свой пароль в URL службы следующим образом (не изменяя часть после @):

postgres://tsdbadmin:YOURPASSWORD@...

Далее это будет называться SERVICEURL в следующих разделах.

3. Создание Hypertable

Timescale позволяет преобразовывать обычные таблицы PostgreSQL в гипертаблицы ↗, таблицы, используемые для работы с временными рядами, событиями или аналитическими данными. После этого изменения Timescale будет автоматически управлять партиционированием hypertable, а также позволит применять другие функции, такие как сжатие или непрерывные агрегаты.

Подключитесь к своей базе данных Timescale, используя Service URL, скопированный на предыдущем шаге (он уже содержит пароль).

Если вы используете стандартный инструмент командной строки PostgreSQL psql ↗ для подключения вы бы запустили psql, как показано ниже (подставив свои URL службы из предыдущего шага). Можно также подключиться с помощью графического инструмента, например PgAdmin ↗.

psql <SERVICEURL>

После подключения создайте таблицу, вставив следующий SQL-код:

CREATE TABLE readings(
  ts timestamptz DEFAULT now() NOT NULL,
  sensor UUID NOT NULL,
  metadata jsonb,
  value numeric NOT NULL
 );

SELECT create_hypertable('readings', 'ts');

Всё остальное Timescale берёт на себя, пока вы загружаете и запрашиваете данные.

4. Создание конфигурации базы данных

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

Hyperdrive использует create команду с --connection-string аргумент, чтобы передать эту информацию. Выполните команду следующим образом:

npx wrangler hyperdrive create hyperdrive --connection-string="SERVICEURL"

Эта команда выводит ID вашего Hyperdrive. Теперь вы можете привязать конфигурацию Hyperdrive к своему Worker в конфигурации Wrangler, заменив содержимое следующим:

{
	"$schema": "./node_modules/wrangler/config-schema.json",
	"name": "timescale-api",
	"main": "src/index.ts",
	// Set this to today's date
	"compatibility_date": "2026-08-28",
	"compatibility_flags": [
		"nodejs_compat"
	],
	"hyperdrive": [
		{
			"binding": "HYPERDRIVE",
			"id": "your-id-here"
		}
	]
}
"$schema" = "./node_modules/wrangler/config-schema.json"
name = "timescale-api"
main = "src/index.ts"
# Set this to today's date
compatibility_date = "2026-08-28"
compatibility_flags = [ "nodejs_compat" ]

[[hyperdrive]]
binding = "HYPERDRIVE"
id = "your-id-here"

Установите драйвер Postgres в проект Worker:

npm i pg

Теперь скопируйте приведенный ниже код Worker и замените им текущий код в ./src/index.ts. Приведенный ниже код:

  1. Использует Hyperdrive для подключения к Timescale со строкой подключения, полученной из env.HYPERDRIVE.connectionString напрямую драйверу.
  2. Создает POST маршрут, который принимает массив показаний JSON для вставки в Timescale в рамках одной транзакции.
  3. Создает GET маршрут, который принимает limit параметр и возвращает самые последние показания. Это можно адаптировать для фильтрации по идентификатору или по временной метке.
import { Client } from "pg";

export interface Env {
	HYPERDRIVE: Hyperdrive;
}

export default {
	async fetch(request, env, ctx): Promise<Response> {
		// Create a new client on each request. Hyperdrive maintains the underlying
		// database connection pool, so creating a new client is fast.
		const client = new Client({
			connectionString: env.HYPERDRIVE.connectionString,
		});
		await client.connect();

		const url = new URL(request.url);
		// Create a route for inserting JSON as readings
		if (request.method === "POST" && url.pathname === "/readings") {
			// Parse the request's JSON payload
			const productData = await request.json();

			// Write the raw query. You are using jsonb_to_recordset to expand the JSON
			// to PG INSERT format to insert all items at once, and using coalesce to
			// insert with the current timestamp if no ts field exists
			const insertQuery = `
      INSERT INTO readings (ts, sensor, metadata, value)
      SELECT coalesce(ts, now()), sensor, metadata, value FROM jsonb_to_recordset($1::jsonb)
      AS t(ts timestamptz, sensor UUID, metadata jsonb, value numeric)
  `;

			const insertResult = await client.query(insertQuery, [
				JSON.stringify(productData),
			]);

			// Collect the raw row count inserted to return
			const resp = new Response(JSON.stringify(insertResult.rowCount), {
				headers: { "Content-Type": "application/json" },
			});

			return resp;

			// Create a route for querying within a time-frame
		} else if (request.method === "GET" && url.pathname === "/readings") {
			const limit = url.searchParams.get("limit");

			// Query the readings table using the limit param passed
			const result = await client.query(
				"SELECT * FROM readings ORDER BY ts DESC LIMIT $1",
				[limit],
			);

			// Return the result as JSON
			const resp = new Response(JSON.stringify(result.rows), {
				headers: { "Content-Type": "application/json" },
			});

			return resp;
		}
	},
} satisfies ExportedHandler<Env>;

5. Разверните Worker

Выполните следующую команду, чтобы повторно развернуть Worker:

npx wrangler deploy

Ваше приложение теперь доступно по адресу timescale-api.<YOUR_SUBDOMAIN>.workers.dev. Точный URI будет показан в выводе только что выполненной команды wrangler.

После развёртывания вы сможете работать с базой данных показаний IoT в Timescale через свой Cloudflare Worker. Подключение с периферии будет быстрее, так как вы используете Cloudflare Hyperdrive.

Теперь Cloudflare Worker можно использовать для добавления новых строк в readings таблица. Чтобы проверить эту функциональность, отправьте POST запрос на URL вашего Worker с /readings путь, а также данные в формате JSON, содержащие данные нового продукта:

[
	{ "sensor": "6f3e43a4-d1c1-4cb6-b928-0ac0efaf84a5", "value": 0.3 },
	{ "sensor": "d538f9fa-f6de-46e5-9fa2-d7ee9a0f0a68", "value": 10.8 },
	{ "sensor": "5cb674a0-460d-4c80-8113-28927f658f5f", "value": 18.8 },
	{ "sensor": "03307bae-d5b8-42ad-8f17-1c810e0fbe63", "value": 20.0 },
	{ "sensor": "64494acc-4aa5-413c-bd09-2e5b3ece8ad7", "value": 13.1 },
	{ "sensor": "0a361f03-d7ec-4e61-822f-2857b52b74b3", "value": 1.1 },
	{ "sensor": "50f91cdc-fd19-40d2-b2b0-c90db3394981", "value": 10.3 }
]

В этом руководстве не рассматривается ts (временную метку) и metadata (JSON-объект), поэтому они будут установлены в now() и NULL соответственно.

После отправки POST запрос вы также можете отправить GET запрос на URL вашего Worker с /readings путь. Задайте limit параметр для управления количеством возвращаемых записей.

Если у вас есть curl установлен, вы можете протестировать его с помощью следующих команд (замените <YOUR_SUBDOMAIN> вашим поддоменом из команды развертывания выше):

Загрузка данных
curl --request POST --data @- 'https://timescale-api.<YOUR_SUBDOMAIN>.workers.dev/readings' <<EOF
[
  { "sensor": "6f3e43a4-d1c1-4cb6-b928-0ac0efaf84a5", "value":0.3},
  { "sensor": "d538f9fa-f6de-46e5-9fa2-d7ee9a0f0a68", "value":10.8},
  { "sensor": "5cb674a0-460d-4c80-8113-28927f658f5f", "value":18.8},
  { "sensor": "03307bae-d5b8-42ad-8f17-1c810e0fbe63", "value":20.0},
  { "sensor": "64494acc-4aa5-413c-bd09-2e5b3ece8ad7", "value":13.1},
  { "sensor": "0a361f03-d7ec-4e61-822f-2857b52b74b3", "value":1.1},
  { "sensor": "50f91cdc-fd19-40d2-b2b0-c90db3394981", "metadata": {"color": "blue" }, "value":10.3}
]
EOF
Запросите данные
curl "https://timescale-api.<YOUR_SUBDOMAIN>.workers.dev/readings?limit=10"

В этом руководстве вы узнали, как создать рабочий пример приема и запроса показаний с периферии на базе Timescale, Workers, Hyperdrive и TypeScript.

Следующие шаги