Cloudflareについては、これまで業務で関わることがなくノータッチできてしまいました。さすがに大体どういうものかは一般教養として知っておかないとまずいと思って調べたときのメモです。
CDNではなく、エッジコンピューティング環境としてのCloudflareにフォーカスしています。
Cloudflare Workers
エッジで動作するJavaScriptのランタイム環境です。コンセプトはAWSのLambda@Edgeに似ていると思います。
CloudflareにはFreeプランがあり、無料で試用できます。
Hono + Cloudflare WorkersでWeb APIを作ってみる
最初にCloudflareでアカウントを作成します。
Honoのチュートリアルに従って、Cloudflare Workers用のHonoプロジェクトを作成します。
npm create hono@latest my-app
cd my-app
npm install
src/index.tsを編集して、/
にHTTP GETでアクセスした時にHelloメッセージを応答するようにします。
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => {
return c.text('Hello Hono!')
})
export default app
まずはローカル環境で実行します。npm run dev
を実行することで、Cloudflare Workersの開発用ツールであるwranglerが動いて、ローカルサーバで動作確認ができます。ブラウザからhttp://localhost:8787
にアクセスするとHello Hono!
メッセージが表示されます。
次にCloudflare上のデプロイします。npm run deploy
でデプロイができます。初めてのデプロイの時には、ブラウザが起動し、Cloudflareへのログインが求められます。
CloudflareのDashboardページでWorkers & Pages
を選択すると、my-appがデプロイできていることが確認できます。
ブラウザからhttps://my-app.<Cloudflareのアカウント名>.workers.dev/
にアクセスすることで、デプロイしたWorkerが動作していることを確認できます。
KV
Cloudflare Workersから利用できるサーバレスなKey-Valueストアサービスです。
KVはCloudflareのFreeプランで利用可能です。
Hono + Cloudflare WorkersからKVを使ってみる
wranglerコマンドを利用してKVに新たな名前空間を作ります。
npx wrangler kv:namespace create "MY_KV"
npx wrangler kv:namespace create --preview "MY_KV"
CloudflareのDashboardを見て、確かにKVに指定した名前空間ができていることを確認します。
Honoのプロジェクトで、wrangler.tomlにKVのBinding情報を追記します。
idとpreview_idには、Dashboardで書くにしたidとpreview_idを設定します。
name = "my-app"
main = "src/index.ts"
compatibility_date = "2024-12-28"
kv_namespaces = [
{ binding = "MY_KV", id = "XXXXX", preview_id = "XXXXX" }
]
index.tsを下記のように変更します。
import { Hono } from 'hono'
import {KVNamespace} from '@cloudflare/workers-types'
type Bindings = {
MY_KV: KVNamespace
}
const app = new Hono<{Bindings: Bindings}>()
app.post('/posts', async (c) => {
const id = Math.random().toString(36).substring(7);
await c.env.MY_KV.put(id, `This is an article of ${id}`);
return c.json({
id: id
}, 201);
});
app.get('/posts/:id', async (c) => {
const id = c.req.param('id');
const value = await c.env.MY_KV.get(id);
return c.json({
id: id,
article: value
}, 200);
});
app.get('/', (c) => {
return c.text('Hello Hono!')
})
npm run dev
でローカル実行して、curlコマンドでPOSTしてGETしてみます。
% curl -X POST http://localhost:8787/posts
{"id":"p6ypkm"}
% curl http://localhost:8787/posts/p6ypkm
{"id":"p6ypkm","article":"This is an article of p6ypkm"}%
npm run deploy
でデプロイして、同様にcurlコマンドで確認します。
KVを使ったアプリがデプロイできていることがわかります。
% curl -X POST http://my-app.<Cloudflareのアカウント名>.workers.dev/posts
{"id":"14k6dt"}
% curl http://my-app.<Cloudflareのアカウント名>.workers.dev/posts/14k6dt
{"id":"14k6dt","article":"This is an article of 14k6dt"}
CloudflareのDashboardからKVにエントリが追加されていることを確認できます。
D1
Cloudflare Workersから利用できるサーバレスな分散SQL DBサービスです。組み込みDBであるSQLiteがベースになっています。
D1はCloudflareのFreeプランで利用可能です。
Hono + Cloudflare WorkersからD1を使ってみる
wranglerコマンドを利用してデータベースを新規作成します。
% npx wrangler d1 create my-app-db
テーブルを作ります。ローカルとリモートに作ります。リモートに作る場合は--remote
オプションをつけます。
npx wrangler d1 execute my-app-db --local --command='CREATE TABLE Users(UserID INT, FirstName TEXT, LastName TEXT)'
npx wrangler d1 execute my-app-db --remote --command='CREATE TABLE Users(UserID INT, FirstName TEXT, LastName TEXT)'
Cloudflare Dashboardでテーブルが作成できたことを確認します。
Honoのプロジェクトで、wrangler.tomlにKVのBinding情報を追記します。
database_idはwranglerコマンドでデータベースを作成した時に出力された値を設定します。
d1_databases = [
{ binding = "MY_DB", database_name = "my-app-db", database_id = "xxxx" }
]
index.tsに下記のコードを追加します。
import { Hono } from 'hono'
import {KVNamespace, D1Database} from '@cloudflare/workers-types'
type Bindings = {
MY_KV: KVNamespace
MY_DB: D1Database
}
type UserInfo = {
firstName: string
lastName: string
}
const app = new Hono<{Bindings: Bindings}>()
app.post('/users', async (c) => {
const userInfo: UserInfo = await c.req.json();
const id = Math.random().toString(36).substring(7);
console.log(userInfo);
await c.env.MY_DB.prepare("INSERT INTO Users (UserID, FirstName, LastName) VALUES (?, ?, ?)").bind(id, userInfo.firstName, userInfo.lastName).run();
return c.json({
id: id
}, 201);
});
app.get('/users/:id', async (c) => {
const id = c.req.param('id');
const { results } = await c.env.MY_DB.prepare("SELECT * FROM Users WHERE UserID = ?").bind(id).all();
if(results.length > 0){
return c.json({
id: id,
firstName: results[0].FirstName,
lastName: results[0].LastName
}, 200);
}else{
return c.json({}, 404);
}
});
npm run dev
でローカル実行して、curlコマンドでPOSTしてGETしてみます。
% curl -X POST -H "Content-Type: application/json" -d '{"firstName":"Nancy","lastName":"Brown"}' http://localhost:8787/users
{"id":"g2j7wq"}
% curl http://localhost:8787/users/g2j7wq
{"id":"g2j7wq","firstName":"Nancy","lastName":"Brown"}
npm run deploy
でデプロイして、同様にcurlコマンドで確認します。
KVを使ったアプリがデプロイできていることがわかります。
% curl -X POST -H "Content-Type: application/json" -d '{"firstName":"Nancy","lastName":"Brown"}' https://my-app.<Cloudflareのアカウント名>.workers.dev/users
{"id":"z6hh6i"}
% curl https://my-app.<Cloudflareのアカウント名>.workers.dev/users/z6hh6i
{"id":"z6hh6i","firstName":"Nancy","lastName":"Brown"}
CloudflareのDashboardからKVにエントリが追加されていることを確認できます。
R2
Cloudflare Workersから利用できるオブジェクトストレージです。
R2はCloudflareのFreeプラインでは利用ができません。
後処理
動作確認が終わったらworkerを削除しておきます。
npx wrangler delete my-app
まとめ
Honoを使って実装したWorkerから、KVやD1が簡単に利用できました。
JavaScriptの実行環境に加えて、オブジェクトストレージ、キーバーリューストア、SQLデータベースが揃っているので、小規模なWebアプリケーションであれば、問題なく実現ができそうです。
コストが安いので、個人開発の場合は、AWSよりも先にCloudflareを検討した方が、良いかもしれません。