Engineer BA-Sulto Tech Blog

カテゴリデータのAPI(CRUD)を実装

カテゴリデータのAPI(CRUD)を実装
2025-06-07
TypeScriptでフルスタック開発マスターへの道・家計簿アプリ開発編

バックエンド構築で作成したcategories_tableテーブルに対して、CRUD操作を行うAPIを作成します。

解説動画

YouTubeに解説動画を公開しています。 こちらもあわせて、ぜひご覧ください。

Honoアプリのインスタンスにベースパスを設定する

まずは、インスタンスHonoに型を設定します。 Bindingsプロパティを追加して、DBプロパティにD1Databaseを指定します。 Bindingsは、Honoが環境変数として受け取るオブジェクトです。 この場合、BindingsにはCloudflare D1を使うための設定を指定しています。 次に、ベースパスを設定します。 引数には、/apiを指定します。 この場合、URLに続けて/apiを追加してAPIに接続できるようになります。

- const app = new Hono(); + const app = new Hono<{ Bindings: { DB: D1Database } }>().basePath("/api");

CRUD操作のAPIを作成する

1. GETメソッド

+ import { drizzle } from "drizzle-orm/d1"; import { Hono } from "hono"; + import { categoriesTable } from "../drizzle/schema/categories"; const app = new Hono<{ Bindings: { DB: D1Database } }>().basePath("/api"); - app.get("/", (c) => { - return c.text("Hello Hono!"); + app.get("/", async (c) => { + try { + const db = drizzle(c.env.DB); + const res = await db.select().from(categoriesTable); + if (res.length === 0) { + return c.json({ error: "登録データがありません" }, 404); + } + return c.json(res); + } catch (e) { + return c.json({ error: e }, 500); + } }); export default app;
  • import { drizzle } from "drizzle-orm/d1" drizzle-orm/d1からdrizzle関数をインポートしています。 これはデータベースとのやり取りを行うための関数です。

  • import { categoriesTable } from "../drizzle/schema/categories" ../drizzle/schema/categoriesからcategoriesTableをインポートしています。 categoriesTableはデータベースのテーブルの定義です。

  • app.get("/", async (c) => {} /へのGETリクエストを処理します。

  • try {} catch (e) {} try catch文で、エラーが発生した場合の処理を行います。

  • const db = drizzle(c.env.DB) 環境変数からDBのインスタンスを取得します。

  • const res = await db.select().from(categoriesTable) selectプロパティを呼び出して、fromメソッドで取得するテーブルの指定します。 categoriesTableを指定して、すべてのデータを取得します。

  • if (res.length === 0) { return c.json({ error: "登録データがありません" }, 404) } データが見つからない場合、404エラーを返します。

  • return c.json(res) データが見つかった場合、JSON形式で返します。

  • return c.json({ error: e }, 500) エラーが発生した場合、500エラーを返します。

+ import { eq } from "drizzle-orm"; import { drizzle } from "drizzle-orm/d1"; import { Hono } from "hono"; import { categoriesTable } from "../drizzle/schema/categories"; + app.get("/:id", async (c) => { + try { + const db = drizzle(c.env.DB); + const id = Number(c.req.param("id")); + const res = await db + .select() + .from(categoriesTable) + .where(eq(categoriesTable.id, id)); + if (res.length === 0) { + return c.json({ error: "データが見つかりません" }, 404); + } + return c.json(res[0]); + } catch (e) { + return c.json({ error: e }, 500); + } + })
  • import { eq } from "drizzle-orm"; drizzle-ormからeq関数をインポートしています。 eq関数は、等価性をチェックする関数です。

  • const id = Number(c.req.param("id")) パラ<!-- -->メータからIDを取得します。

  • where(eq(categoriesTable.id, id)) whereプロパティを呼び出して、eq関数で更新するレコードの条件を指定します。

  • return c.json(res[0]) データが見つかった場合、JSON形式で返します。 受け取ったデータは配列なので、0番目のデータを返します。

2. POSTメソッド

export type Category = typeof categoriesTable.$inferInsert
import { eq } from "drizzle-orm"; import { drizzle } from "drizzle-orm/d1"; import { Hono } from "hono"; - import { categoriesTable } from "../drizzle/schema/categories"; + import { categoriesTable, Category } from "../drizzle/schema/categories"; + app.post("/", async (c) => { + try { + const db = drizzle(c.env.DB); + const { name } = await c.req.json<Category>(); + await db.insert(categoriesTable).values({ name }); + return c.json({ message: "データを追加しました" }, 201); + } catch (e) { + return c.json({ error: e }, 500); + } + });
  • import { categoriesTable, Category } from "../drizzle/schema/categories"; Categoryを追加でインポートしています。 CategorycategoriesTableの型です。

  • app.post("/", async (c) => {} /へのPOSTリクエストを処理します。

  • const { name } = await c.req.json<Category>() リクエストボディからJSONデータを取得し、Category型として解析しています。

  • await db.insert(categoriesTable) insertプロパティを呼び出して、categoriesTableを指定して、データを追加します。

  • values({ name }) valuesプロパティを呼び出して、nameを指定して、データを追加します。

  • return c.json({ message: "データを追加しました" }, 201); 追加結果をJSON形式で返します。

3. PUTメソッド

app.put("/:id", async (c) => { try { const db = drizzle(c.env.DB); const id = Number(c.req.param("id")); const { name } = await c.req.json<Category>(); await db .update(categoriesTable) .set({ name }) .where(eq(categoriesTable.id, id)); return c.json({ message: "データを更新しました" }, 200); } catch (e) { return c.json({ error: e }, 500); } });
  • app.put("/:id", async (c) => {} /:idへのPUTリクエストを処理します。

  • await db.update(categoriesTable) updateプロパティを呼び出して、categoriesTableを指定して、データを更新します。

  • set({ name }) setプロパティを呼び出して、nameを指定して、データを更新します。

  • return c.json({ message: "データを更新しました" }, 200); 更新結果をJSON形式で返します。

4. DELETEメソッド

app.delete("/:id", async (c) => { try { const db = drizzle(c.env.DB); const id = Number(c.req.param("id")); await db.delete(categoriesTable).where(eq(categoriesTable.id, id)); return c.json({ message: "データを削除しました" }, 200); } catch (e) { return c.json({ error: e }, 500); } });
  • app.delete("/:id", async (c) => {} /:idへのDELETEリクエストを処理します。

  • await db.delete(categoriesTable) deleteプロパティを呼び出して、categoriesTableを指定して、データを削除します。

  • return c.json({ message: "データを削除しました" }, 200); 削除結果をJSON形式で返します。

タグ

ExpoReact NativeTypeScriptCloudflare WorkersHonoCloudflare D1