Elysia入門 - Bun向けWebフレームワークの型安全性と選定ポイント

8分 で読める | 2024.12.29

公式ドキュメント

ElysiaはTypeScriptでWeb APIを構築するためのフレームワークです。Bun向けに設計され、route、schema validation、lifecycle hook、plugin、OpenAPI連携、型付きclientのEdenなどを提供します。

この記事の結論

記事情報: 2024年12月29日初出。Elysia公式ドキュメントを2026年7月25日に再確認しています。

Elysiaの特徴は、server側のroute schemaからrequest・responseの型を推論し、必要ならEdenを通じてclientへ共有できる点です。一方、「最速」という単一のベンチマークだけで選ぶべきではありません。Bunでの運用経験、pluginの成熟度、OpenAPIを境界にするか、clientとserverを同じTypeScript型で結ぶかを含めて判断します。

最小のAPI

ElysiaではHTTP methodとpathをchainしてrouteを定義します。

import { Elysia } from "elysia";

const app = new Elysia()
  .get("/", () => ({ message: "Hello" }))
  .get("/users/:id", ({ params }) => ({
    id: params.id,
  }))
  .listen(3000);

console.log(`Listening on ${app.server?.port}`);

導入はBunを前提にした公式手順を確認します。

bun create elysia app
cd app
bun run dev

Elysia自体はWeb Standard APIを重視し、adapterを通じた別runtimeの選択肢も案内されています。ただしpluginや機能が同じ範囲で動くとは限りません。Bun以外を対象にする場合は、対象adapterの公式ページと制限を確認します。

schema validationと型推論

Elysiaのtを使うと、body、query、params、headers、responseにschemaを定義できます。実行時には入力を検証し、TypeScript側ではhandlerの型として推論されます。

import { Elysia, t } from "elysia";

const app = new Elysia().post(
  "/users",
  ({ body }) => ({
    id: crypto.randomUUID(),
    name: body.name,
  }),
  {
    body: t.Object({
      name: t.String({ minLength: 1, maxLength: 80 }),
    }),
    response: t.Object({
      id: t.String(),
      name: t.String(),
    }),
  },
);

TypeScriptの型注釈だけは実行時に消えます。外部から届くJSONを守るには、route schemaによる実行時検証が必要です。文字列長やformatだけでなく、業務上の権限や一意性はservice層・DB側でも検証します。

response schemaを定義すると、APIの契約が明確になります。ただし内部エラーの詳細をそのまま返さないよう、正常応答とエラー応答を設計し、ログへ残す情報とclientへ返す情報を分けてください。

lifecycle hook

Elysiaはrequestの受信からresponseまでに複数のlifecycleを持ち、onRequestbeforeHandleafterHandleonErrorなどで共通処理を登録できます。

const app = new Elysia()
  .onRequest(({ request }) => {
    console.log(request.method, new URL(request.url).pathname);
  })
  .onError(({ code, error, set }) => {
    set.status = code === "VALIDATION" ? 400 : 500;

    return {
      error: code === "VALIDATION" ? "invalid_request" : "internal_error",
    };
  });

hookは便利ですが、順序と適用範囲を理解せず増やすと処理を追いにくくなります。認証、logging、error mappingなど責務ごとにpluginへ分け、route固有の処理はhandlerの近くへ置きます。

また、秘密情報やrequest body全体をログへ出さないようにします。認証header、cookie、password、token、個人情報は明示的に除外してください。

pluginとscope

再利用するrouteやhookはElysia instanceとしてまとめ、useで組み込めます。

const healthPlugin = new Elysia({ name: "health" })
  .get("/health", () => ({ status: "ok" }));

const app = new Elysia()
  .use(healthPlugin)
  .listen(3000);

Elysiaのlifecycle hookにはlocal、scoped、globalなどの適用範囲があります。pluginを作るときは「登録先のrouteだけに効くのか、親や後続routeにも効くのか」を公式のscope資料で確認します。

第三者pluginを採用する場合は、対応するElysia・Bunのversion、保守状況、認証やerror handlingへの影響を調べます。pluginが少ないこと自体を避ける理由にする必要はありませんが、重要機能を自分たちで保守できるかは運用判断になります。

Edenによるend-to-end型安全性

Eden Treatyは、Elysia serverの型をTypeScript clientへ渡し、routeをobjectのように呼び出す仕組みです。code generationを使わず、TypeScriptの型推論でrequestとresponseを結びます。

// server.ts
export const app = new Elysia()
  .get("/users/:id", ({ params }) => ({ id: params.id }));

export type App = typeof app;
// client.ts
import { treaty } from "@elysiajs/eden";
import type { App } from "./server";

const api = treaty<App>("http://localhost:3000");
const { data, error } = await api.users({ id: "42" }).get();

serverとclientを同じmonorepoで管理する場合は、変更が型へすぐ反映される利点があります。一方、別言語のclient、外部公開API、独立releaseでは、TypeScript型だけを契約にすると利用者が限定されます。その場合はOpenAPIを公開契約にし、Edenは内部clientに限定する設計も考えられます。

型安全性は認証や認可を保証しません。正しい型のidが届いても、その利用者が対象resourceを読めるとは限らないため、server側で権限を検証します。

OpenAPI・WebSocket・stream

Elysiaは公式pluginを通じてOpenAPI documentを生成できます。schemaをrouteの近くに置くと、validation、型、API documentのずれを減らせます。ただしdescription、認証方式、error response、exampleなどは自動推論だけでは不十分な場合があり、公開前に生成結果を確認します。

WebSocketやstreaming responseも扱えます。採用時には通常requestだけでなく、接続切断、backpressure、timeout、proxyの設定、graceful shutdownを試します。localで接続できることと、本番のload balancerを通して安定することは同じではありません。

アプリの構成

小規模APIでも、すべてを1つのchainへ書き続けるとテストが難しくなります。次のように責務を分けると保守しやすくなります。

  • route: HTTPの入力・出力schemaとstatus
  • service: 業務ルール
  • repository: DBや外部API
  • plugin: 認証、logging、共通error処理
  • client contract: EdenまたはOpenAPI

handlerでは入力を受け、serviceを呼び、HTTP responseへ変換する範囲に留めます。DB queryや複雑な業務ルールをroute chainへ直接埋め込まないようにします。

選定チェックリスト

Elysiaを検討するときは、サンプルの短さや公開ベンチマークだけでなく、次を実際の要件で確認します。

  1. 対象runtimeとdeployment先が公式に対応しているか
  2. DB driver、認証、監視SDKが動くか
  3. schemaから期待するOpenAPIが生成されるか
  4. Edenの型共有がrepository構成に合うか
  5. error、shutdown、WebSocket再接続をテストできるか
  6. version更新時のbreaking changeを追えるか

Elysiaは、BunとTypeScriptを中心に、実行時validationと型推論を近づけたいAPIに向いています。既存Node.js資産をそのまま使うことや、公開APIの長期互換性を優先する場合は、依存パッケージと契約管理を先に検証してください。

参考リソース

← 一覧に戻る
PR
PR
PR
PR