https://qiita.com/advent-calendar/2023/hono
In my university class, I'm developing an ios app as a team. The app needed a backend, so I decided to use the hottest technology stack, Hono and Cloudflare Workers, to implement the backend. It's an MVP, so I didn't do anything fancy.
Needless to say.
This too.
I needed a database, so I used it.
It's a TypeScript ORM that also supports D1. It's hot.
As a requirement of this app, there was a photo posting, so I used it as a storage location.
Since I'm using Cloudflare Workers, I need to set up Wrangler. First of all,
npm install -g wrangler
and then,
wrangler login
If you can log in successfully, create a project with
wrangler init [project name]
I referred to the following articles.
D1 setup is done with
wrangler d1 create [database name]
and then add the following to wrangler.toml.
[[ d1_databases ]]
binding = "DB"
database_name = "<your-database-name>"
database_id = "<your-id>"
I referred to the following articles for the drizzle setup (I omitted it because it's a bit off topic).
I'm lazy to type wrangler d1 migrations apply dbtest, so I added the following two to package.json.
"scripts": {
"deploy": "wrangler deploy",
"dev": "wrangler dev",
"start": "wrangler dev",
+ "generate": "drizzle-kit generate:sqlite --out migrations --schema src/db/schema.ts",
+ "migration": "wrangler d1 migrations apply dbtest"
},
I referred to yusukebe's article for the R2 setup. https://yusukebe.com/posts/2022/r2-beta/
As usual,
wrangler r2 bucket create [bucket name]
to create a bucket and then add it to wrangler.toml.
[[ r2_buckets ]]
binding = 'BUCKET'
bucket_name = '<your-bucket-name>'
preview_bucket_name = '<your-bucket-name>'
Setup of Hono is done with
npm create hono@latest
and then select
cloudflare-workers
from the options.
I'll just introduce the parts that stand out, as long as they meet the requirements.
First, the implementation of photo posting.
app.put('/post', async (c) => {
const data = await c.req.json<PostData>();
const base64 = data.key;
if (!base64) return c.notFound();
const type = detectType(base64);
if (!type) return c.notFound();
const body = Uint8Array.from(atob(base64), (c) => c.charCodeAt(0));
let key;
key = (await sha256(body)) + '.' + type?.suffix;
if (c.env) {
const bucket = c.env.BUCKET;
await bucket.put(key, body, { httpMetadata: { contentType: type.mimeType } });
} else {
throw new Error('c.env is undefined');
}
const db = drizzle(c.env.DB);
await db
.insert(posts)
.values({
userId: data.userId,
title: data.title,
key: key,
createdAt: data.createdAt,
latitude: data.latitute,
longitude: data.longitude,
isPublic: data.isPublic,
isFriendsOnly: data.isFriendsOnly,
isPrivate: data.isPrivate,
orientation: data.orientation,
})
.execute();
const result = await db.select().from(posts).where(eq(posts.key, key)).all();
return c.json({ id: result[0].id, userId: data.userId, title: data.title, key: key });
});
To explain in detail,
The photo data comes in base64, so I referred to yusukebe's code and saved it in the bucket.
const body = Uint8Array.from(atob(base64), (c) => c.charCodeAt(0));
let key;
key = (await sha256(body)) + '.' + type?.suffix;
if (c.env) {
const bucket = c.env.BUCKET;
await bucket.put(key, body, { httpMetadata: { contentType: type.mimeType } });
} else {
throw new Error('c.env is undefined');
}
It's a complete copy. Thank you for yusukebe.
Then, I saved it in the database with the help of drizzle.
const db = drizzle(c.env.DB);
await db
.insert(posts)
.values({
userId: data.userId,
title: data.title,
key: key,
createdAt: data.createdAt,
latitude: data.latitute,
longitude: data.longitude,
isPublic: data.isPublic,
isFriendsOnly: data.isFriendsOnly,
isPrivate: data.isPrivate,
orientation: data.orientation,
})
.execute();
I was able to experience the ease of development using Hono and Cloudflare Workers. As a beginner, I was able to code intuitively and deploy easily, so I think it's perfect for beginners. It's nice to be able to deploy the code I wrote immediately and check it out, and it also helps to keep my motivation up. It's very helpful for me, who is easily bored. In conclusion, Hono and Cloudflare Workers are the best.
https://qiita.com/advent-calendar/2023/hono
私が通っている大学の授業の一環として、iosアプリのチーム開発を行っています。そのアプリでバックエンドが必要になり、せっかくなので今アツい技術スタックを使ってみたい!!!ということで、HonoとCloudflare Workersを使ってバックエンドを実装しました。といってもMVPなので、大層なことはしていません。
言わずもがなですね。
これもそう。
データベースが欲しかったので使いました。
D1にも対応しているTypeScriptのORMです。アツい。
今回のアプリの要件として、写真の投稿があったので、その保存先として使いました。
Cloudflare Workersを使っているので、Wranglerのセットアップが必要。 とりま、
npm install -g wrangler
して、
wrangler login
をする。無事にログインできたら、
wrangler init [project name]
でプロジェクトを作成します。
私は、以下の記事を参考にしました。
D1のセットアップは、
wrangler d1 create [database name]
で出来ちゃいます。 あとはwrangler.tomlに、追加するだけ。
[[ d1_databases ]]
binding = "DB"
database_name = "<your-database-name>"
database_id = "<your-id>"
drizzle周りのセットアップは参考の記事に書いてある通りです(本題から若干外れるので割愛)。
migrationのコマンドを打つのが面倒なので、package.jsonに以下の二つを追加しました。
"scripts": {
"deploy": "wrangler deploy",
"dev": "wrangler dev",
"start": "wrangler dev",
+ "generate": "drizzle-kit generate:sqlite --out migrations --schema src/db/schema.ts",
+ "migration": "wrangler d1 migrations apply dbtest"
},
R2のセットアップは、yusukebeさんの記事を参考にしました。 https://yusukebe.com/posts/2022/r2-beta/
例の如く、
wrangler r2 bucket create [bucket name]
でバケットを作成して、
wrangler.tomlに追加します。
[[ r2_buckets ]]
binding = 'BUCKET'
bucket_name = '<your-bucket-name>'
preview_bucket_name = '<your-bucket-name>'
Honoのセットアップは、
npm create hono@latest
を叩いて、選択肢のうち
cloudflare-workers
を選択します。そうすれば色々生成されるので、src/に色々書いていけばおkです。
要件に沿って実装していけばいいので、特出するところだけ紹介します。
まず、写真の投稿の実装ですが、
app.put('/post', async (c) => {
const data = await c.req.json<PostData>();
const base64 = data.key;
if (!base64) return c.notFound();
const type = detectType(base64);
if (!type) return c.notFound();
const body = Uint8Array.from(atob(base64), (c) => c.charCodeAt(0));
let key;
key = (await sha256(body)) + '.' + type?.suffix;
if (c.env) {
const bucket = c.env.BUCKET;
await bucket.put(key, body, { httpMetadata: { contentType: type.mimeType } });
} else {
throw new Error('c.env is undefined');
}
const db = drizzle(c.env.DB);
await db
.insert(posts)
.values({
userId: data.userId,
title: data.title,
key: key,
createdAt: data.createdAt,
latitude: data.latitute,
longitude: data.longitude,
isPublic: data.isPublic,
isFriendsOnly: data.isFriendsOnly,
isPrivate: data.isPrivate,
orientation: data.orientation,
})
.execute();
const result = await db.select().from(posts).where(eq(posts.key, key)).all();
return c.json({ id: result[0].id, userId: data.userId, title: data.title, key: key });
});
という感じです。
詳しく説明すると、
写真のデータはbase64で来るので、yusukebeさんのコードを参考にして、バケットに保存しています。
const body = Uint8Array.from(atob(base64), (c) => c.charCodeAt(0));
let key;
key = (await sha256(body)) + '.' + type?.suffix;
if (c.env) {
const bucket = c.env.BUCKET;
await bucket.put(key, body, { httpMetadata: { contentType: type.mimeType } });
} else {
throw new Error('c.env is undefined');
}
まるパクリですね。ありがとうございます。
あとは、drizzleの恩恵に預かって、データベースに保存しています。
const db = drizzle(c.env.DB);
await db
.insert(posts)
.values({
userId: data.userId,
title: data.title,
key: key,
createdAt: data.createdAt,
latitude: data.latitute,
longitude: data.longitude,
isPublic: data.isPublic,
isFriendsOnly: data.isFriendsOnly,
isPrivate: data.isPrivate,
orientation: data.orientation,
})
.execute();
モバイルアプリじゃなくてもいいやんというツッコミはさておき、HonoとCloudflare Workersを使ってみて、開発体験の良さを実感しました。初心者の私が直感的にコーディングできて、デプロイも簡単なので、入門には最適だと思います。書いたコードを即座にデプロイして、動作確認ができるのは気持ちがよく、モチベーションの維持にも繋がると思います。何かと飽き性な筆者には、とてもありがたいです。結論、HonoとCloudflare Workersは最高です。