Back

Koaで初めてのAPIを構築する

Koaで初めてのAPIを構築する

JavaScriptを知っていてバックエンドAPIを構築したいなら、Koaは真剣に検討する価値があります。ミニマルでモダン、そしてasync/awaitを基盤から組み込んでいるため、よりクリーンなコードでコールバック地獄を回避できます。このKoa APIチュートリアルでは、プロジェクトのセットアップ、ミドルウェアの仕組みの理解、そしてGETとPOSTエンドポイントを持つ小規模なREST APIの構築という基本を順を追って説明します。

重要なポイント

  • Koaは軽量なNode.jsフレームワークで、バンドルされたミドルウェアがなく、必要なものだけを組み合わせます。
  • 「オニオンモデル」のミドルウェアカスケードにより、各関数は下流のハンドラーの前後でロジックを実行できます。
  • ctxオブジェクトがリクエストとレスポンスのデータを統合し、ルートハンドラーをクリーンで読みやすく保ちます。
  • @koa/router@koa/bodyparserを使えば、1つのファイルで動作するREST APIを立ち上げることができます。

前提条件

  • Node.js 20以上(現在のLTS推奨)
  • async/awaitを含む基本的なJavaScriptの知識
  • ターミナルとテキストエディタ

Koaとは何か、なぜ使うのか?

KoaはExpressの開発チームによって作られた軽量なNode.js Webフレームワークです。Expressとは異なり、Koaにはバンドルされたミドルウェアがありません。必要なものだけを追加します。その際立った特徴はミドルウェアカスケードで、「オニオンモデル」とも呼ばれ、各ミドルウェア関数がチェーン内の次の関数のの両方でコードを実行します。

これにより、Koa APIの基本は理解しやすくなります。すべてのリクエストはミドルウェアスタックを内側に流れ、レスポンスは外側に戻っていきます。

ステップ1 — プロジェクトのセットアップ

新しいディレクトリを作成して初期化します:

mkdir koa-items-api && cd koa-items-api
npm init -y

ESモジュール構文を使用するためにpackage.json"type": "module"を追加し、依存関係をインストールします:

npm install koa @koa/router @koa/bodyparser
  • koa — コアフレームワーク
  • @koa/router — 公式ルーティングミドルウェア
  • @koa/bodyparser — 受信するJSONリクエストボディをパースします

ステップ2 — KoaミドルウェアAPIを理解する

すべてのKoaミドルウェアは、ctx(コンテキスト)オブジェクトとnext関数を受け取るasync関数です。ctxオブジェクトはリクエストとレスポンスを1つの場所にまとめます。ctx.methodctx.pathctx.request.body、そしてctx.body(レスポンス)はすべてそこに存在します。

await next()を呼び出すと、次のミドルウェアに制御が渡されます。以下は簡単なログ記録の例です:

app.use(async (ctx, next) => {
  const start = Date.now()
  await next()
  console.log(`${ctx.method} ${ctx.path} — ${Date.now() - start}ms`)
})

await next()のコードは、下流のミドルウェアが完了した後に実行されることに注意してください。これがオニオンモデルの動作です。

ステップ3 — KoaでREST APIを構築する

小規模なインメモリアイテムAPIを持つapp.jsを作成します:

import Koa from "koa"
import Router from "@koa/router"
import  bodyParser  from  "@koa/bodyparser"

const app = new Koa()
const router = new Router()

// インメモリデータストア
let nextId = 3
let items = [
  { id: 1, name: "Keyboard" },
  { id: 2, name: "Monitor" },
]

// GET /items — すべてのアイテムを返す
router.get("/items", (ctx) => {
  ctx.body = { success: true, data: items }
})

// GET /items/:id — 1つのアイテムを返す
router.get("/items/:id", (ctx) => {
  const item = items.find((i) => i.id === Number(ctx.params.id))
  if (!item) {
    ctx.status = 404
    ctx.body = { error: "Item not found" }
    return
  }
  ctx.body = { success: true, data: item }
})

// POST /items — 新しいアイテムを作成
router.post("/items", (ctx) => {
  const { name } = ctx.request.body
  if (!name) {
    ctx.status = 400
    ctx.body = { error: "Name is required" }
    return
  }
  const newItem = { id: nextId++, name }
  items.push(newItem)
  ctx.status = 201
  ctx.body = { success: true, data: newItem }
})

app.use(bodyParser())
app.use(router.routes())
app.use(router.allowedMethods())

app.listen(3000, () => console.log("Server running on http://localhost:3000"))

注意: 元のid: items.length + 1のアプローチは、アイテムを削除すると配列の長さが縮小する一方で既存のIDは変わらないため、問題が発生します。別のnextIdカウンターを使用することで、重複したIDを回避できます。

サーバーを起動します:

node app.js

エンドポイントをテストする

すべてのアイテムを取得:

curl http://localhost:3000/items

アイテムを作成:

curl -X POST http://localhost:3000/items \
  -H "Content-Type: application/json" \
  -d '{"name": "Mouse"}'

期待されるレスポンス:

{ "success": true, "data": { "id": 3, "name": "Mouse" } }

存在しないアイテムをリクエスト:

curl http://localhost:3000/items/99
{ "error": "Item not found" }

router.allowedMethods()は、サポートされていないHTTPメソッドを自動的に処理し、追加のコードなしで適切な405 Method Not Allowedレスポンスを返します。

まとめ

Koaの強みはそのシンプルさです。ctxオブジェクトはリクエストとレスポンスの処理を1つの場所にまとめ、ミドルウェアカスケードはリクエストがアプリケーションを通過する方法を正確に制御できます。この基盤—Koaサーバー、ルーティング用の@koa/router、JSONパース用の@koa/bodyparser—は、KoaでREST APIを構築し始めるために必要なすべてです。ここから、実際のデータベース、バリデーション、またはエラーハンドリングミドルウェアを一度に1つのレイヤーずつ追加できます。

よくある質問

Koaには組み込みのミドルウェアが付属していないため、プロジェクトに必要なものだけをインストールします。また、コールバックの代わりにasync/awaitをネイティブに使用するため、エラーハンドリングと制御フローが簡素化されます。Expressは従来のコールバックベースのミドルウェアシグネチャに依存していますが、Koaのオニオンモデルでは各ミドルウェアが下流のハンドラーの前後でロジックを実行できます。

はい。Koaは安定しており、よくメンテナンスされており、多くのチームが本番環境で使用しています。設計上ミニマルであるため、独自のルーター、ボディパーサー、エラーハンドリングレイヤーを選択します。これにより、依存関係スタックを完全に制御でき、フレームワークのフットプリントを小さく保つことができ、監査と長期的なメンテナンスを簡素化できます。

ミドルウェアスタックの最上部にtry/catchミドルウェアを配置します。KoaはAsync/awaitを使用するため、下流でスローされたエラーはすべてその外側のハンドラーにバブルアップします。その後、ctx.statusとctx.bodyを設定して一貫したエラーレスポンスを返すことができます。この単一のミドルウェアにより、すべてのルートで繰り返しエラーチェックを行う必要がなくなります。

はい。Koaおよび@koa/routerや@koa/bodyparserなどの公式パッケージには、TypeScriptの型定義が含まれています。ts-nodeまたはビルドステップを使用して標準的なTypeScriptプロジェクトをセットアップし、通常どおりKoaをインポートして、ctxオブジェクト、ルートパラメータ、リクエストボディに対して完全な型安全性を得ることができます。

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay