このチュートリアルでは、Timescale ↗(クラウド上で PostgreSQL を高速化します)に保存した時系列データを取り込み、照会する API を Workers 上に構築します。
データの取り込み用 API ルートを公開する Worker 関数を作成してデプロイし、Hyperdrive ↗ でエッジからデータベース接続をプロキシします。コネクションプールを維持し、リクエストごとに新しいデータベース接続を作らないようにします。
次の内容を学びます。
- Cloudflare Worker の構築とデプロイ
- Wrangler CLI での Worker シークレットの利用
- Timescale データベースサービスのデプロイ
- Hyperdrive で Worker を Timescale データベースサービスへ接続する
- 新しい API の照会
Timescale の詳細は、Timescale の ドキュメント ↗ を参照してください。
次のコマンドを実行し、コマンドラインから Worker プロジェクトを作成します。
npm create cloudflare@latest -- timescale-apiyarn create cloudflare timescale-apipnpm create cloudflare@latest timescale-apiセットアップでは、次のオプションを選びます。
- What would you like to start with? では、
Hello World exampleを選びます。 - Which template would you like to use? では、
Worker onlyを選びます。 - Which language do you want to use? では、
TypeScriptを選びます。 - Do you want to use git for version control? では、
Yesを選びます。 - Do you want to deploy your application? では、
Noを選びます(デプロイ前にいくつか変更します)。
アプリケーションがデプロイされた URL を控えておきます。GitHub webhook を設定するときに使います。
作成した Worker プロジェクトのディレクトリへ移動します。
cd timescale-api新しいサービスを作成する場合は、Timescale Console ↗ を開き、次の手順を行います。
- 右上の黒いプラスを選び、Create Service を選択します。
- サービスの種類として Time Series を選びます。
- 希望のリージョンとインスタンスサイズを選びます。このチュートリアルでは 1 CPU で十分です。
- ランダム生成された名前を、任意のサービス名に置き換えます。
- Create Service を選択します。
- 右側で Connection Info ダイアログを展開し、Service URL をコピーします。
- 表示されたパスワードをコピーします。あとから再表示できません。
- I stored my password, go to service overview を選択します。
以前作成したサービスを使う場合は、Timescale Console ↗ で接続情報を確認できます。
- Hyperdrive を接続するサービス(データベース)を選びます。
- Connection info を展開します。
- Service URL をコピーします。Service URL は Hyperdrive が接続に使う接続文字列です。この文字列には、データベースのホスト名、ポート番号、データベース名が含まれます。
Service URL にパスワードを次のように挿入します(@ 以降はそのままにします)。
postgres://tsdbadmin:YOURPASSWORD@...以降のセクションでは、これを SERVICEURL と呼びます。
Timescale では、通常の PostgreSQL テーブルを hypertables ↗(時系列、イベント、分析データを扱うテーブル)へ変換できます。この変更後、Timescale が hypertable のパーティショニングを透過的に管理し、圧縮や継続的な集計などの機能も適用できます。
前の手順でコピーした Service URL(パスワードを含みます)で、Timescale データベースへ接続します。
デフォルトの PostgreSQL CLI ツール psql ↗ で接続する場合は、次のように実行します(前の手順の Service 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 が管理します。
新しい Hyperdrive インスタンスを作成するには、次が必要です。
- 手順 2 の SERVICEURL
- Hyperdrive サービスの名前。このチュートリアルでは hyperdrive を使います。
Hyperdrive は create コマンドと --connection-string 引数でこの情報を渡します。次のように実行します。
npx wrangler hyperdrive create hyperdrive --connection-string="SERVICEURL"このコマンドは Hyperdrive ID を出力します。Wrangler 設定の内容を次に置き換え、Hyperdrive 構成を Worker にバインドします。
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "timescale-api",
"main": "src/index.ts",
// Set this to today's date
"compatibility_date": "2026-09-20",
"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-09-20"
compatibility_flags = [ "nodejs_compat" ]
[[hyperdrive]]
binding = "HYPERDRIVE"
id = "your-id-here"Postgres ドライバーを Worker プロジェクトへインストールします。
npm i pgyarn add pgpnpm add pgbun add pg次の Worker コードをコピーし、./src/index.ts の現在のコードを置き換えます。このコードは次を行います。
env.HYPERDRIVE.connectionStringから生成した接続文字列をドライバーへ直接渡し、Hyperdrive 経由で Timescale へ接続します。- JSON の readings 配列を受け取り、1 つのトランザクションで Timescale へ挿入する
POSTルートを作成します。 limitパラメーターを受け取り、最新の readings を返すGETルートを作成します。ID やタイムスタンプで絞り込むように拡張できます。
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>;次のコマンドを実行し、Worker を再デプロイします。
npx wrangler deployアプリケーションは timescale-api.<YOUR_SUBDOMAIN>.workers.dev で公開されます。正確な URI は、今実行した wrangler コマンドの出力に表示されます。
デプロイ後は、Cloudflare Worker から Timescale の IoT readings データベースを操作できます。Cloudflare Hyperdrive でエッジから接続するため、エッジからの接続はより高速になります。
Cloudflare Worker から readings テーブルへ新しい行を挿入できます。動作確認するには、Worker の URL の /readings パスへ、新しい製品データを含む JSON ペイロード付きの POST リクエストを送ります。
[
{ "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 リクエストを送ったあと、Worker の URL の /readings パスへ GET リクエストも送れます。返す件数は 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}
]
EOFcurl "https://timescale-api.<YOUR_SUBDOMAIN>.workers.dev/readings?limit=10"このチュートリアルでは、Timescale、Workers、Hyperdrive、TypeScript を使い、エッジから readings を取り込み、照会する動作例を作成しました。
- Hyperdrive の仕組み を確認してください。
- Timescale ↗ の詳細を確認してください。
- よくある問題の切り分けは トラブルシューティングガイド を参照してください。