Elysia - Bun向け最速Webフレームワーク

2024.12.29

公式ドキュメント

Elysiaとは

Elysiaは、Bunランタイム向けに最適化された高速なWebフレームワークです。End-to-End型安全性、エルゴノミックなAPI、驚異的なパフォーマンスが特徴です。

パフォーマンス

ベンチマーク(リクエスト/秒):

  • Express (Node.js): 15,000
  • Fastify (Node.js): 45,000
  • Hono (Bun): 120,000
  • Elysia (Bun): 150,000+

基本的な使い方

import { Elysia } from 'elysia';

const app = new Elysia()
 .get('/', () => 'Hello, Elysia!')
 .get('/user/:id', ({ params: { id } }) => `User ${id}`)
 .post('/users', ({ body }) => body)
 .listen(3000);

console.log(`🦊 Server running at ${app.server?.url}`);

型安全性

ポイント: ElysiaではスキーマをTypeBox(t.Object等)で定義すると、リクエスト/レスポンスの型が自動推論され、バリデーションも同時に行われます。

自動型推論

import { Elysia, t } from 'elysia';

const app = new Elysia()
 .post('/users', ({ body }) => {
 // bodyは自動的に型付け
 return { id: 1, ...body };
 }, {
 body: t.Object({
 name: t.String(),
 email: t.String({ format: 'email' }),
 age: t.Optional(t.Number())
 }),
 response: t.Object({
 id: t.Number(),
 name: t.String(),
 email: t.String(),
 age: t.Optional(t.Number())
 })
 });

実践メモ: Eden(@elysiajs/eden)を使えば、サーバー側の型定義をクライアントで直接参照でき、tRPCのようなEnd-to-End型安全を実現できます。

End-to-End型安全クライアント

// server.ts
import { Elysia, t } from 'elysia';

export const app = new Elysia()
 .get('/users', () => [{ id: 1, name: 'Alice' }])
 .get('/users/:id', ({ params }) => ({ id: params.id, name: 'Alice' }))
 .post('/users', ({ body }) => ({ id: 1, ...body }), {
 body: t.Object({ name: t.String() })
 });

export type App = typeof app;

// client.ts
import { treaty } from '@elysiajs/eden';
import type { App } from './server';

const client = treaty<App>('http://localhost:3000');

// 完全な型推論
const users = await client.users.get();
const user = await client.users({ id: '1' }).get();
const newUser = await client.users.post({ name: 'Bob' });

プラグインシステム

組み込みプラグイン

import { Elysia } from 'elysia';
import { swagger } from '@elysiajs/swagger';
import { cors } from '@elysiajs/cors';
import { jwt } from '@elysiajs/jwt';

const app = new Elysia()
 .use(swagger())
 .use(cors())
 .use(jwt({
 name: 'jwt',
 secret: process.env.JWT_SECRET!
 }))
 .get('/protected', async ({ jwt, cookie: { auth } }) => {
 const profile = await jwt.verify(auth.value);
 if (!profile) throw new Error('Unauthorized');
 return profile;
 });

注意: ElysiaはBunランタイム専用です。Node.jsプロジェクトでは動作しないため、環境要件を事前に確認しましょう

カスタムプラグイン

import { Elysia } from 'elysia';

const myPlugin = new Elysia({ name: 'my-plugin' })
 .decorate('myService', {
 greet: (name: string) => `Hello, ${name}!`
 })
 .derive(({ headers }) => ({
 userId: headers['x-user-id']
 }));

const app = new Elysia()
 .use(myPlugin)
 .get('/', ({ myService, userId }) => {
 return myService.greet(userId ?? 'Guest');
 });

ライフサイクル

const app = new Elysia()
 // リクエスト前
 .onBeforeHandle(({ request }) => {
 console.log(`${request.method} ${request.url}`);
 })
 // レスポンス後
 .onAfterHandle(({ response }) => {
 console.log('Response sent');
 })
 // エラーハンドリング
 .onError(({ error, code }) => {
 console.error(`Error: ${code}`, error);
 return { error: error.message };
 })
 .get('/', () => 'Hello');

グループとガード

const app = new Elysia()
 .group('/api', (app) =>
 app
 .guard({
 beforeHandle: ({ headers }) => {
 if (!headers['authorization']) {
 throw new Error('Unauthorized');
 }
 }
 })
 .get('/users', () => [])
 .get('/posts', () => [])
 )
 .listen(3000);

ポイント: Elysiaはジェネレーター関数とReadableStreamの両方でストリーミングレスポンスをサポートしています。

ストリーミング

import { Elysia } from 'elysia';

const app = new Elysia()
 .get('/stream', function* () {
 yield 'Hello ';
 yield 'World ';
 yield '!';
 })
 .get('/sse', ({ set }) => {
 set.headers['content-type'] = 'text/event-stream';
 return new ReadableStream({
 start(controller) {
 let count = 0;
 const interval = setInterval(() => {
 controller.enqueue(`data: ${count++}\n\n`);
 if (count >= 10) {
 clearInterval(interval);
 controller.close();
 }
 }, 1000);
 }
 });
 });

WebSocket

import { Elysia } from 'elysia';

const app = new Elysia()
 .ws('/ws', {
 message(ws, message) {
 ws.send(`Echo: ${message}`);
 },
 open(ws) {
 console.log('Connection opened');
 },
 close(ws) {
 console.log('Connection closed');
 }
 });

Swagger自動生成

import { Elysia, t } from 'elysia';
import { swagger } from '@elysiajs/swagger';

const app = new Elysia()
 .use(swagger({
 documentation: {
 info: { title: 'My API', version: '1.0.0' }
 }
 }))
 .get('/users', () => [], {
 response: t.Array(t.Object({
 id: t.Number(),
 name: t.String()
 })),
 detail: {
 summary: 'Get all users',
 tags: ['users']
 }
 });

// http://localhost:3000/swagger でドキュメント表示

Elysiaを評価する観点

ElysiaはBunとの組み合わせで高い性能を出しやすいWebフレームワークです。Bunを前提にしたプロジェクトでは魅力がありますが、Node.js環境や既存Express資産が中心のチームでは、ランタイムごとの違いも確認する必要があります。

採用判断では、型安全なルーティング、プラグイン、バリデーション、テスト、デプロイ先をまとめて見ます。速さだけでなく、チームが運用できる周辺エコシステムがそろっているかが重要です。

向いているケース

  • Bunを本格的に採用している
  • 小さく高速なAPIサーバーを作りたい
  • TypeScriptの型推論を活かしたルート定義をしたい
  • 新規プロジェクトでランタイム選定から見直せる

まとめ

Elysiaは、Bunの性能を最大限に活かした高速なWebフレームワークです。End-to-End型安全性とエルゴノミックなAPIにより、型安全なフルスタックアプリケーションを効率的に構築できます。

参考リソース

← 一覧に戻る
PR
PR
PR
PR