📜
Hono+D1で掲示板
挨拶
あけましておめでとうございます
taisan11です
今回は掲示板を作ったので紹介?解説?をしていきたいと思います
先に完成品がこちらです(多分こっち見た方が早い)
リポジトリ名は適当なので...
使ったもの
- Hono
- drizzleorm
- cloudflare D1
- cloudflare workers
機能
2024/1現在以下の機能が実装されています
- スレッド一覧を閲覧(直近20個のみ)(GET)
- スレッド内を閲覧(GET)
- スレッド作成(POST)
- レス投稿(POST)
全てAPI形式となっていて、UIがありません
それぞれのコード
適当に紹介するだけです
DB
DB設計
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
// スレッド
export const threads = sqliteTable("threads", {
id: integer("id").primaryKey().notNull(), //スレッドID(タイムスタンプ)
title: text("title").notNull(), //スレタイ
createdAt: text("created_at").notNull(), //投稿日時
ip_addr: text("ip_addr").notNull(), //投稿者IPアドレス
isDelete: integer("isDelete", { mode: "boolean" }).notNull().default(false), // 削除フラグ
});
// レス
export const post = sqliteTable("post", {
ex_id: integer("ex_id").primaryKey().notNull(), //投稿ID(非公開)(スレッドID+レス番号+乱数)
id: integer("id").notNull().references(() => threads.id), //スレッドID(タイムスタンプ)
res_id: integer("res_id").notNull(), //レス番号(0001~1000まで)
name: text("name").notNull(), //投稿者名
mail: text("mail"), //任意!!投稿者メールアドレス(キャップ可)
message: text("message").notNull(), //投稿内容
createdAt: text("created_at").notNull(), //投稿日時
ip_addr: text("ip_addr").notNull(), //投稿者IPアドレス
isDelete: integer("isDelete", { mode: "boolean" }).notNull().default(false), // 削除フラグ
});
スレッド一覧を閲覧
app.get("/api/threads", async (c) => {
const db = drizzle(c.env.DB, { schema });
const result = await db.select().from(threads).limit(10).execute();//ここで取得
return c.json(result.map((record) => ({ [record.id]: record.title })));
});
map関数で必要なものだけをJsonで再生成
スレッド内を閲覧
app.get("/api/threads/:threadid", async (c) => {
const threadidIn = c.req.param("threadid");
const threadidDate = parseInt(threadidIn);
const db = drizzle(c.env.DB);
const result2 = await db.select().from(post).where(eq(post.id, threadidDate));
return c.json(result2);
});
スレッドにresを追加するやつ(関数?)
関数にしてまとめたかったけど無理だった
//スレッドにレスを追加
console.debug(body.id);
let resulta = await db.query.post.findFirst({
where: (post, { eq }) => eq(post.id, body.id),
orderBy: (post, { desc }) => [desc(post.res_id)],
});
if (!resulta) {
//@ts-ignore
resulta = { res_id: 1 }; // resultaがundefinedの場合に新しいオブジェクトを代入
}
console.debug(resulta);
if (!resulta) {
// レコードが存在しない場合の処理をここに書く
return c.text("指定されたIDのレコードが存在しません");
}
const record = resulta; // 最初のレコードを取得
const ex_id = Number(`${record.res_id + 1}${body.id}${Math.floor(Math.random() * 88) + 10}`,);
const res_id = Number(`${record.res_id + 1}`);
const id = Number(`${body.id}`);
console.debug(body.mail);
//@ts-ignore
let kextuka;
if (!body.mail) {
console.debug("mailないよ");
kextuka = await db
.insert(post)
.values({
ex_id: ex_id,
id: id,
res_id: res_id,
name: body.name,
message: body.message,
createdAt: new Date().toISOString(),
ip_addr: body.ip_addr,
// user_id: body.user_id,
})
.execute();
} else {
console.debug("mailあるよ");
kextuka = await db
.insert(post)
.values({
ex_id: ex_id,
id: body.id,
res_id: record.res_id + 1,
name: body.name,
mail: body.mail,
message: body.message,
createdAt: new Date().toISOString(),
ip_addr: body.ip_addr,
// user_id: body.user_id,
).execute();
})
スレッドにレスを追加するやつ
app.post("/api/post/:threadid", async (c) => {
// dataの確認
if (await dataConfirmation(c, true)) {
return dataConfirmation(c, true);
}
const body = await c.req.json();
const db = drizzle(c.env.DB, { schema });
if (!body.id) {
return c.text("すれIDがないよ");
}
//スレッドにレスを追加(省略)
return c.text(String(kextuka.success));
});
ここ関数にしたかった...関数にしたらこんなに省略できるのに...
いつか考えよ
スレッド作るやつ
app.post("/api/newThread", async (c) => {
if (await dataConfirmation(c, false)) {
return dataConfirmation(c, false);
}
const body = await c.req.json();
const db = drizzle(c.env.DB, { schema });
if (!body.title) {
return c.text("すれタイがないよ");
}
const date = new Date();
const UnixTime = date.getTime();
//スレッド一覧にスレッドを追加
const result = await db
.insert(threads)
.values({
id: UnixTime,
title: body.title,
createdAt: new Date().toISOString(),
ip_addr: body.ip_addr,
})
.returning({ insertedId: threads.id })
.execute();
//スレッドにレスを追加(省略)(微妙に違うけどいいや)
return c.json(result);
});
最後に
いつかUIも作ることを目標にします。
次回→やる予定(UI編)
Discussion