はじめに
Honoを使って、シンプルなTodo APIを作りました。
今回作ったAPIでは、Todoの一覧取得、追加、完了状態の更新ができます。
また、React側からfetchでAPIを呼び出し、取得したデータを画面に反映するところまで実装しました。
この記事では、HonoでAPIを作る流れと、フロントエンドからAPIを呼び出す流れを中心にまとめます。
HonoでAPIのエンドポイントを作り、ReactからそのAPIを呼び出すことで、Web APIの基本的な流れを理解することを目的にしています。
Prismaを使ったDB操作、PostgreSQLとの接続、Docker Composeでの環境構築、CORSについては別の記事で整理する予定です。
HonoでAPIサーバーを作る
まず、Honoを使ってAPIサーバーを作ります。
Honoでは、new Hono()でアプリケーションを作成します。
import { serve } from "@hono/node-server";
import { Hono } from "hono";
const app = new Hono();
作成したappに対して、app.get()やapp.post()のようなメソッドを使ってエンドポイントを定義します。
app.get("/", (c) => {
return c.text("Hello Hono!");
});
最後に、serve()を使ってサーバーを起動します。
serve(
{
fetch: app.fetch,
hostname: "0.0.0.0",
port: 3000,
},
(info) => {
console.log(`Server is running on http://localhost:${info.port}`);
},
);
ここではport: 3000を指定しているので、APIサーバーはhttp://localhost:3000で起動します。
作ったもの
Todoを管理するシンプルなAPIを作りました。
できることは以下の3つです。
- Todo一覧を取得する
- 新しいTodoを追加する
- Todoの完了状態を更新する
APIのエンドポイントは、以下のように用意しました。
GET /todos
POST /todos
PUT /todos/:id
GET /todosでは、Todoの一覧を取得してJSONで返しています。
app.get("/todos", async (c) => {
const todos = await prisma.todo.findMany();
return c.json({ todos });
});
POST /todosでは、リクエストボディからtitleを受け取り、その値をもとに新しいTodoを作成します。作成したTodoは、JSONとしてレスポンスで返します。
const { title } = await c.req.json();
// 〜〜DBにデータを入れる処理〜〜
return c.json({ todo });
PUT /todos/:idでは、URLからidを受け取り、リクエストボディからcompletedを受け取ってTodoの完了状態を更新しています。
const { id } = c.req.param();
const { completed } = await c.req.json();
ReactからAPIを呼び出す
React側からは、これらのAPIをfetchで呼び出しています。
fetchではmethodを指定しない場合、デフォルトでGETリクエストになります。
const response = await fetch("http://localhost:3000/todos");
const data = await response.json();
setTodos(data.todos as Todo[]);
Todoを追加するときは、POST /todosにJSONを送ります。
const response = await fetch("http://localhost:3000/todos", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ title: title.trim() }),
});
完了状態を更新するときは、PUT /todos/:idを呼び出します。
const response = await fetch(`http://localhost:3000/todos/${id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
completed: !todos.find((todo) => todo.id === id)?.completed,
}),
});
APIを作るだけでなく、フロントエンドから実際に呼び出すところまで実装したことで、APIがどのように画面とつながるのかを確認できました。
学んだこと
-
HonoでTodo APIを作ってみて、APIを作る流れが分かった
-
Honoでは、
app.get()やapp.post()のようにHTTPメソッドごとの関数を使ってエンドポイントを定義できる
そのため、どのURLにどのHTTPメソッドでアクセスしたときに、どの処理を行うのかがコード上でわかりやすいと感じました。
- HTTPメソッドごとの役割も整理できました。
GET -> データを取得する
POST -> データを新しく作成する
PUT -> 既存のデータを更新する
今回のTodo APIでは、Todo一覧の取得にGET、Todoの追加にPOST、完了状態の更新にPUTを使いました。
実際にTodoアプリに当てはめて使ってみることで、それぞれの役割をイメージしやすくなりました。
- APIでは、JSONを使ってデータをやり取りすることも学んだ
Hono側ではc.json()を使ってJSONのレスポンスを返し、React側ではresponse.json()を使ってレスポンスをJavaScriptのオブジェクトとして扱いました。
const data = await response.json();
setTodos(data.todos as Todo[]);
取得したデータをReactのstateに保存することで、APIのレスポンスを画面に反映できます。
また、フロントエンドとAPIの役割分担も少し理解できました。
フロントエンド:画面表示やユーザー操作を担当
API:Todoの取得・追加・更新といった処理を担当
fetchを使ってその2つをつなぐことで、画面からAPIを呼び出してデータを扱えるようになりました。
APIだけを作るのではなく、Reactから実際に呼び出すところまで実装したことで、Web APIがフロントエンドとどうつながるのかを体験できたのが大きな学びでした。
今後学ぶ(整理する)こと
今回は、HonoでAPIを作る流れと、ReactからAPIを呼び出す流れを中心に学びました。
一方で、まだ理解を深めたい部分もあります。
- Prismaを使ってDBにデータを保存する仕組み
- CORSについて
PostgreSQLとの接続についても、別で整理したいです。
APIからDBに接続してデータを保存する流れや、テーブル設計、マイグレーションについても理解を深めたいと思っています。
また、ReactとAPIを別のポートで動かすときに、なぜCORSの設定が必要になるのかをきちんと理解したいと思っています。
そのほかにも、バリデーションやエラーハンドリングなど、APIをより実用的にするために必要なことを学んでいきたいです。