HonoでAPI構築 Durable Objectsも使っちゃうよ

Hono - Web framework built on Web Standards # Quick Start

を見てinstallする。そして

pnpm run deploy

で表示される***.workers.devにアクセス

Hello Hono!を確認。非常にspeedy。


OpenAPI doc & swagger UIを導入する

https://hono.dev/examples/swagger-ui?utm_source=chatgpt.com

を見ながら、swaggerのmiddlewareを入れる。こういうのが簡単に入れられるのもありがたい。client側もopenapiで合わせて生成したいので...

import { swaggerUI } from '@hono/swagger-ui'
import { Hono } from 'hono'

const openApiDoc = {
openapi: '3.0.0', // This is the required version field
info: {
title: 'API Documentation',
version: '1.0.0',
description: 'API documentation for your service',
},
paths: {
// Add your API paths here
'/health': {
get: {
summary: 'Health check',
responses: {
'200': {
description: 'OK',
},
},
},
},
// Add more endpoints as needed
},
}

const app = new Hono()

app.get('/', (c) => {
return c.text('Hello Hono!')
})

// Serve the OpenAPI document
app.get('/doc', (c) => c.json(openApiDoc))

// Use the middleware to serve Swagger UI at /ui
app.get('/ui', swaggerUI({ url: '/doc' }))

app.get('/health', (c) => c.text('OK'))

export default app


Cloudflare Durable Objectsを使用する

https://developers.cloudflare.com/durable-objects/get-started/#1-create-a-worker-project

に倣って、別projectとして一旦durable objectを使用したprojectをデプロイする。


先程honoで作成したprojectのほうにもDurable Objectsを適用するためには、wrangler.jsonc (またはwrangler.toml)及びDurableObjects用のクラスを作成する必要があることがわかる。


以下をwrangler.jsoncに追加する。

"durable_objects": {
"bindings": [
{
"name": "DO_NAME",
"class_name": "TypeScriptClassName"
}
]
},
"migrations": [
{
"tag": "v1",
"new_sqlite_classes": ["TypeScriptClassName"]
}
]

DO_NAMEとなっている箇所にはDurable Objectsの名前を、TypeScriptClassNameとなっている箇所には後ほど定義するTypeScriptのクラス名を記載する。


TypeScriptClassName.tsで以下のようにクラスを定義する。

export class TypeScriptClassName extends DurableObject<Env> {
private sql: SqlStorage;

constructor(ctx: DurableObjectState, env: Env) {
super(ctx, env);
this.sql = ctx.storage.sql;

this.sql.exec(`
CREATE TABLE IF NOT EXISTS sample_table (
id INTEGER PRIMARY KEY
, uuid BLOG(16) UNIQUE NOT NULL
);
`);
}

async insert(): Promise<void> {
this.sql.exec(`INSERT INTO dive_queue (uuid) VALUES (?)`, [
crypto.randomUUID()
]);
}
}


honoのindex.tsで以下のようにgetStub utilityメソッドを用意する。

このときEnvはworker-configuration.d.tsで定義されたものを使用する。

worker-configuration.d.tsはpnpm wrangler typesコマンドに寄ってwrangler.jsonc(またはtoml)を見て生成される。

Durable Objectsの内容に更新がある場合は都度コマンドの実行が必要。

ref. https://developers.cloudflare.com/workers/languages/typescript/

function getStub(env: Env): DurableObjectStub<DiveQueue> {
const id = env.DO_NAME.idFromName('global');
return env.DO_NAME.get(id) as DurableObjectStub<DiveQueue>;
}


このとき、idFromNameを一定のglobalなどにすると全リクエストで同一のDurable Objectsインスタンスを参照 / 更新することになり簡易的な単一ストレージのように使用することができる。

ref. https://developers.cloudflare.com/durable-objects/api/namespace/#methods


https://developers.cloudflare.com/durable-objects/api/sqlite-storage-api/

使用することができるSQL APIはここを見ると良い。


localで開発する際に、wranglerがモックしているDurable Objectsをリセットしたい場合は.wranglerディレクトリを削除すると良い。


Durable Objects - alarmを使用する

https://developers.cloudflare.com/durable-objects/api/alarms/

ゴミデータをあとから削除するなど、遅延実行や定期実行をしたい場合にDurable Objectsのアラーム機能を使用することができる。

Related Articles