fastify
Fastifyは、高速なAPI開発のために設計されたNode.jsのWebフレームワークで、JSONスキーマによる検証やプラグイン機構、ライフサイクルフックなどを備え、開発効率とパフォーマンス向上を両立するSkill。
📜 元の英語説明(参考)
Fastify is a high-performance Node.js web framework focused on developer experience and low overhead. It features JSON Schema validation, a powerful plugin system, lifecycle hooks, and automatic serialization for blazing-fast APIs.
🇯🇵 日本人クリエイター向け解説
Fastifyは、高速なAPI開発のために設計されたNode.jsのWebフレームワークで、JSONスキーマによる検証やプラグイン機構、ライフサイクルフックなどを備え、開発効率とパフォーマンス向上を両立するSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o fastify.zip https://jpskill.com/download/14890.zip && unzip -o fastify.zip && rm fastify.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/14890.zip -OutFile "$d\fastify.zip"; Expand-Archive "$d\fastify.zip" -DestinationPath $d -Force; ri "$d\fastify.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
fastify.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
fastifyフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 1
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
Fastify
Fastify は、最も高速な Node.js ウェブフレームワークの一つです。JSON Schema を介してリクエストを検証し、レスポンスを自動的にシリアライズし、カプセル化されたプラグインシステムを通じてコードを整理します。
インストール
# Fastify プロジェクトの作成
mkdir my-api && cd my-api
npm init -y
npm i fastify @fastify/autoload @fastify/sensible @fastify/cors @fastify/jwt
プロジェクト構成
# 推奨される Fastify プロジェクトのレイアウト
src/
├── app.js # アプリケーションファクトリ
├── server.js # エントリーポイント
├── plugins/ # 共有プラグイン (db, auth)
│ ├── db.js
│ └── auth.js
├── routes/ # ルートモジュール
│ ├── articles/
│ │ ├── index.js # ルートハンドラ
│ │ └── schema.js # JSON スキーマ
│ └── health.js
└── test/
└── articles.test.js
アプリケーションのセットアップ
// src/app.js — autoload を使用したアプリケーションファクトリ
import Fastify from 'fastify';
import autoload from '@fastify/autoload';
import sensible from '@fastify/sensible';
import cors from '@fastify/cors';
import { join } from 'node:path';
export function buildApp(opts = {}) {
const app = Fastify({ logger: true, ...opts });
app.register(sensible);
app.register(cors, { origin: true });
app.register(autoload, { dir: join(import.meta.dirname, 'plugins') });
app.register(autoload, { dir: join(import.meta.dirname, 'routes'), options: { prefix: '/api' } });
return app;
}
// src/server.js — サーバーの起動
import { buildApp } from './app.js';
const app = buildApp();
app.listen({ port: 3000, host: '0.0.0.0' }, (err) => {
if (err) { app.log.error(err); process.exit(1); }
});
スキーマ検証付きのルート
// src/routes/articles/schema.js — JSON Schema の定義
export const articleSchema = {
type: 'object',
properties: {
id: { type: 'integer' },
title: { type: 'string' },
body: { type: 'string' },
createdAt: { type: 'string', format: 'date-time' },
},
};
export const createArticleSchema = {
body: {
type: 'object',
required: ['title', 'body'],
properties: {
title: { type: 'string', maxLength: 200 },
body: { type: 'string' },
},
},
response: { 201: articleSchema },
};
// src/routes/articles/index.js — article CRUD ルート
import { createArticleSchema } from './schema.js';
export default async function articleRoutes(fastify) {
fastify.get('/', async (request) => {
const { page = 1, limit = 20 } = request.query;
const offset = (page - 1) * limit;
const { rows } = await fastify.db.query(
'SELECT * FROM articles ORDER BY created_at DESC LIMIT $1 OFFSET $2',
[limit, offset]
);
return rows;
});
fastify.get('/:id', async (request, reply) => {
const { rows } = await fastify.db.query('SELECT * FROM articles WHERE id = $1', [request.params.id]);
if (!rows[0]) return reply.notFound();
return rows[0];
});
fastify.post('/', { schema: createArticleSchema, preHandler: [fastify.authenticate] }, async (request, reply) => {
const { title, body } = request.body;
const { rows } = await fastify.db.query(
'INSERT INTO articles (title, body) VALUES ($1, $2) RETURNING *',
[title, body]
);
return reply.code(201).send(rows[0]);
});
}
プラグイン
// src/plugins/db.js — pg を使用したデータベースプラグイン
import fp from 'fastify-plugin';
import pg from 'pg';
export default fp(async function dbPlugin(fastify) {
const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });
fastify.decorate('db', pool);
fastify.addHook('onClose', () => pool.end());
});
// src/plugins/auth.js — JWT 認証プラグイン
import fp from 'fastify-plugin';
import jwt from '@fastify/jwt';
export default fp(async function authPlugin(fastify) {
fastify.register(jwt, { secret: process.env.JWT_SECRET || 'dev-secret' });
fastify.decorate('authenticate', async function (request, reply) {
try {
await request.jwtVerify();
} catch (err) {
reply.unauthorized();
}
});
});
フック
// src/app.js — ライフサイクルフックの例 (buildApp 内に追加)
app.addHook('onRequest', async (request) => {
request.startTime = process.hrtime.bigint();
});
app.addHook('onResponse', async (request, reply) => {
const duration = Number(process.hrtime.bigint() - request.startTime) / 1e6;
request.log.info({ duration: `${duration.toFixed(2)}ms`, status: reply.statusCode }, 'request completed');
});
エラー処理
// src/app.js — カスタムエラーハンドラ (buildApp 内に追加)
app.setErrorHandler((error, request, reply) => {
request.log.error(error);
const status = error.statusCode || 500;
reply.code(status).send({
error: error.name,
message: status === 500 ? 'Internal Server Error' : error.message,
});
});
テスト
// src/test/articles.test.js — ビルトインの inject を使用したテスト
import { test } from 'node:test';
import assert from 'node:assert';
import { buildApp } from '../app.js';
test('GET /api/articles returns 200', async () => {
const app = buildApp({ logger: false });
const response = await app.inject({ method: 'GET', url: '/api/articles' });
assert.strictEqual(response.statusCode, 200);
await app.close();
});
主要なパターン
- 同じカプセル化コンテキストを共有する必要があるプラグインには、
fastify-plugin(fp) を使用します。 - バリデーションには JSON Schema を使用します。これにより、高速化のために自動シリアライゼーションも生成されます。
- ディレクトリからプラグインとルートを自動登録するには、
@fastify/autoloadを使用します。 - 共有サービス (db, cache) には、fastify インスタンスをデコレートします (
fastify.decorate)。 .notFound()、.unauthorized()などのヘルパーには、@fastify/sensibleを使用します。- Fastify は async-first です。
reply.send()を呼び出す代わりに、ハンドラから値を返します。
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
Fastify
Fastify is one of the fastest Node.js web frameworks. It validates requests via JSON Schema, serializes responses automatically, and organizes code through an encapsulated plugin system.
Installation
# Create Fastify project
mkdir my-api && cd my-api
npm init -y
npm i fastify @fastify/autoload @fastify/sensible @fastify/cors @fastify/jwt
Project Structure
# Recommended Fastify project layout
src/
├── app.js # App factory
├── server.js # Entry point
├── plugins/ # Shared plugins (db, auth)
│ ├── db.js
│ └── auth.js
├── routes/ # Route modules
│ ├── articles/
│ │ ├── index.js # Route handler
│ │ └── schema.js # JSON schemas
│ └── health.js
└── test/
└── articles.test.js
App Setup
// src/app.js — application factory with autoload
import Fastify from 'fastify';
import autoload from '@fastify/autoload';
import sensible from '@fastify/sensible';
import cors from '@fastify/cors';
import { join } from 'node:path';
export function buildApp(opts = {}) {
const app = Fastify({ logger: true, ...opts });
app.register(sensible);
app.register(cors, { origin: true });
app.register(autoload, { dir: join(import.meta.dirname, 'plugins') });
app.register(autoload, { dir: join(import.meta.dirname, 'routes'), options: { prefix: '/api' } });
return app;
}
// src/server.js — start the server
import { buildApp } from './app.js';
const app = buildApp();
app.listen({ port: 3000, host: '0.0.0.0' }, (err) => {
if (err) { app.log.error(err); process.exit(1); }
});
Routes with Schema Validation
// src/routes/articles/schema.js — JSON Schema definitions
export const articleSchema = {
type: 'object',
properties: {
id: { type: 'integer' },
title: { type: 'string' },
body: { type: 'string' },
createdAt: { type: 'string', format: 'date-time' },
},
};
export const createArticleSchema = {
body: {
type: 'object',
required: ['title', 'body'],
properties: {
title: { type: 'string', maxLength: 200 },
body: { type: 'string' },
},
},
response: { 201: articleSchema },
};
// src/routes/articles/index.js — article CRUD routes
import { createArticleSchema } from './schema.js';
export default async function articleRoutes(fastify) {
fastify.get('/', async (request) => {
const { page = 1, limit = 20 } = request.query;
const offset = (page - 1) * limit;
const { rows } = await fastify.db.query(
'SELECT * FROM articles ORDER BY created_at DESC LIMIT $1 OFFSET $2',
[limit, offset]
);
return rows;
});
fastify.get('/:id', async (request, reply) => {
const { rows } = await fastify.db.query('SELECT * FROM articles WHERE id = $1', [request.params.id]);
if (!rows[0]) return reply.notFound();
return rows[0];
});
fastify.post('/', { schema: createArticleSchema, preHandler: [fastify.authenticate] }, async (request, reply) => {
const { title, body } = request.body;
const { rows } = await fastify.db.query(
'INSERT INTO articles (title, body) VALUES ($1, $2) RETURNING *',
[title, body]
);
return reply.code(201).send(rows[0]);
});
}
Plugins
// src/plugins/db.js — database plugin with pg
import fp from 'fastify-plugin';
import pg from 'pg';
export default fp(async function dbPlugin(fastify) {
const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });
fastify.decorate('db', pool);
fastify.addHook('onClose', () => pool.end());
});
// src/plugins/auth.js — JWT auth plugin
import fp from 'fastify-plugin';
import jwt from '@fastify/jwt';
export default fp(async function authPlugin(fastify) {
fastify.register(jwt, { secret: process.env.JWT_SECRET || 'dev-secret' });
fastify.decorate('authenticate', async function (request, reply) {
try {
await request.jwtVerify();
} catch (err) {
reply.unauthorized();
}
});
});
Hooks
// src/app.js — lifecycle hooks example (add inside buildApp)
app.addHook('onRequest', async (request) => {
request.startTime = process.hrtime.bigint();
});
app.addHook('onResponse', async (request, reply) => {
const duration = Number(process.hrtime.bigint() - request.startTime) / 1e6;
request.log.info({ duration: `${duration.toFixed(2)}ms`, status: reply.statusCode }, 'request completed');
});
Error Handling
// src/app.js — custom error handler (add inside buildApp)
app.setErrorHandler((error, request, reply) => {
request.log.error(error);
const status = error.statusCode || 500;
reply.code(status).send({
error: error.name,
message: status === 500 ? 'Internal Server Error' : error.message,
});
});
Testing
// src/test/articles.test.js — testing with built-in inject
import { test } from 'node:test';
import assert from 'node:assert';
import { buildApp } from '../app.js';
test('GET /api/articles returns 200', async () => {
const app = buildApp({ logger: false });
const response = await app.inject({ method: 'GET', url: '/api/articles' });
assert.strictEqual(response.statusCode, 200);
await app.close();
});
Key Patterns
- Use
fastify-plugin(fp) for plugins that should share the same encapsulation context - Use JSON Schema for validation — it also generates automatic serialization for speed
- Use
@fastify/autoloadto auto-register plugins and routes from directories - Decorate the fastify instance (
fastify.decorate) for shared services (db, cache) - Use
@fastify/sensiblefor.notFound(),.unauthorized(), etc. helpers - Fastify is async-first: return values from handlers instead of calling
reply.send()