plugins/web/skills/building-nodejs-services/SKILL.md
Build backend services, web servers, and CLI tools on the Node.js runtime using the Fastify framework. Use when package.json contains fastify, when defining Fastify routes, plugins, hooks, or JSON-schema validation, or when working with Node runtime internals (event loop phases, libuv, streams, buffers, clustering, worker threads, blocking-the-event-loop avoidance) beyond browser-level JavaScript. Covers Fastify routing and request/reply, schema-based validation and serialization (AJV/JSON Schema), the plugin and encapsulation model, Pino logging, server-side rendering with EJS/Handlebars, RESTful CRUD APIs, persistence with Mongoose/Sequelize/SQLite/Redis, session/cookie and JWT authentication flows, message queues (RabbitMQ/amqplib), CLI tooling (process stdio, promisify, CSV), external data integration (fetch, feed aggregation, scraping via cheerio/Puppeteer), email and generative-AI service integration, and project scaffolding (npm init, ESM, node --watch).
npx skillsauth add sumik5/sumik-claude-plugin building-nodejs-servicesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Node ランタイム上で Fastify を用いてバックエンドサービス・Web サーバー・CLI ツールを構築するためのクイックリファレンス。詳細な実装ガイドは references/ を参照する。
本スキルは以下の状況で起動する:
package.json の dependencies または devDependencies に fastify が含まれている自動起動:
disable-model-invocation: falseにより、Fastify 関連ファイルが文脈に存在するとき自動的に本スキルが適用される。devkit のルーティング hook を別途更新するまでは、fastify検出時に本スキルが自動起動するかどうかは description ベースの文脈判断に依存する。
Node のイベントループはシングルスレッドで非同期 I/O を多重化する。CPU バウンドな同期処理(ネストしたループ・巨大データ変換・暗号演算)はイベントループを停止させ、全リクエストの応答を遅延させる。
判断ルール:
fs.promises / ORM / fetch)worker_threads か外部プロセスへオフロードsetInterval / setTimeout 内での重い処理 → スタック分割か setImmediate でサイクルを明け渡すFastify はルート定義時に JSON Schema を受け取り、AJV でリクエストバリデーションとレスポンスシリアライゼーションを事前コンパイルする。
利点:
response スキーマによりシリアライズが高速化される(未定義フィールドを自動除去)// スキーマ付きルートの骨格
app.post('/items', {
schema: {
body: {
type: 'object',
required: ['name', 'price'],
properties: {
name: { type: 'string', maxLength: 100 },
price: { type: 'number', minimum: 0 }
}
},
response: {
201: {
type: 'object',
properties: {
id: { type: 'string' },
name: { type: 'string' }
}
}
}
}
}, async (request, reply) => {
reply.code(201).send({ id: crypto.randomUUID(), name: request.body.name });
});
Fastify のプラグインは fastify.register() で追加し、スコープ内に装飾・ルート・フックを閉じ込める。親スコープには自動で漏れない(encapsulation)。fastify-plugin(fp)でラップすると親スコープへ公開できる。
// 認証フックをプラグインとして切り出す例
import fp from 'fastify-plugin';
const authPlugin = async (fastify) => {
fastify.addHook('preHandler', async (request, reply) => {
if (!request.headers.authorization) {
reply.code(401).send({ error: 'Unauthorized' });
}
});
};
export default fp(authPlugin);
Fastify はデフォルトで Pino ロガーを内蔵する。request.log.info() / request.log.error() で JSON 構造化ログを出力する。console.log を本番コードに残してはならない。
const app = Fastify({ logger: { level: process.env.LOG_LEVEL ?? 'info' } });
app.get('/health', async (request) => {
request.log.info({ reqId: request.id }, 'health check called');
return { status: 'ok' };
});
DB 接続文字列・JWT シークレット・外部 API キーをコードにハードコードしてはならない。dotenv または Node 20+ の --env-file フラグを使い、.env をリポジトリに含めない(.gitignore に追加する)。
| 負荷特性 | 推奨手法 |
|---------|---------|
| I/O 多い・CPU 軽い | 単一プロセス(デフォルト)で十分 |
| マルチコアを活かしたい | cluster モジュールで CPU コア数分のワーカープロセスを起動 |
| CPU バウンド処理あり | worker_threads でメインスレッドから重い計算を分離 |
スケール判断は実測(プロファイリング)ベースで行う。過早な最適化を避ける。
// index.js(ESM モード: package.json に "type":"module" を追加)
import Fastify from 'fastify';
const app = Fastify({ logger: true });
const PORT = Number(process.env.PORT) || 3000;
app.get('/', async () => ({ message: 'hello' }));
try {
await app.listen({ port: PORT, host: '0.0.0.0' });
} catch (err) {
app.log.error(err);
process.exit(1);
}
ポイント:
Fastify({ logger: true }) でリクエストログが自動付与されるhost: '0.0.0.0' を指定してコンテナ環境でも外部からアクセス可能にするprocess.exit(1) でクラッシュを明示し壊れた状態で動き続けないようにする// URL パラメータ・クエリ文字列の取得
app.get('/users/:id', async (request) => {
const { id } = request.params; // /users/42 → id = '42'
const { page } = request.query; // ?page=2 → page = '2'
return { id, page };
});
// JSON ボディを受け取る POST
app.post('/users', async (request, reply) => {
const user = request.body; // Content-Type: application/json が必要
reply.code(201).send(user);
});
reply オブジェクトの主要メソッド| メソッド | 用途 |
|---------|------|
| reply.send(data) | ボディを送信(型に応じて Content-Type 自動決定) |
| reply.code(n) | HTTP ステータスコードを設定(チェーン可能) |
| reply.header(k, v) | レスポンスヘッダーを追加 |
| reply.redirect(url) | 3xx リダイレクト |
node --watch index.js # Node 18.11+ の組み込み watch モード
timers → pending callbacks → idle/prepare → poll → check → close callbacks
| フェーズ | 実行内容 |
|---------|---------|
| timers | setTimeout / setInterval のコールバック |
| pending callbacks | 前のループで defer された I/O コールバック |
| poll | 新しい I/O イベントの取得と実行 |
| check | setImmediate のコールバック |
| close callbacks | socket.destroy() 等の close イベント |
process.nextTick と queueMicrotask(Promise の .then)は各フェーズの直後に実行されるマイクロタスクキューに入り、次フェーズに持ち越されない。
stream.pipeline(source, transform, dest, cb) または stream/promises の pipeline でエラー伝播を自動管理する(手動の .pipe() より推奨)| 処理 | ブロッキングリスク | 対処 |
|------|------------------|------|
| ファイル読み書き | なし(libuv が非同期処理) | fs.promises / ストリーム |
| DB クエリ | なし(I/O オフロード) | ORM / ドライバの async API |
| JSON.parse(大サイズ) | あり | ワーカースレッドへオフロード |
| 正規表現(バックトラック) | あり | timeout 付き外部プロセスで実行 |
| 暗号演算(pbkdf2 等) | あり | util.promisify(crypto.pbkdf2) |
libuv のスレッドプールサイズはデフォルト 4。
UV_THREADPOOL_SIZE環境変数で最大 128 まで拡張可能。
判断が分岐する局面では推測せず確認する。以下のシグナルを検出したら AskUserQuestion を使う:
| 検出シグナル | 確認すべき内容 | 選択肢の骨子 | |-------------|-------------|------------| | データを永続化する | 永続化レイヤの選択 | SQLite / PostgreSQL(Sequelize) / MongoDB(Mongoose) / Redis | | 認証が必要 | 認証方式の選択 | セッション/Cookie(SSR アプリ)/ JWT(ステートレス API) | | キュー・非同期処理が必要 | キュー技術の選択 | インメモリ / Redis / RabbitMQ | | HTML を返すページがある | テンプレートエンジン | EJS(JS 埋め込み)/ Handlebars(ロジックレス) | | 高負荷・マルチコア活用 | スケール手法 | 単一プロセス / clustering / worker threads |
確認が不要な推奨事項(既定で適用):
node:crypto の scrypt/pbkdf2 で安全にハッシュ化するconsole.log を本番コードに残さない)⚠️ Codex fallback:
AskUserQuestionツールが使えない環境では、判断が必要な箇所に// TODO: 要件に応じて変更コメントを挿入し、複数パターンのコード断片を列挙して人間が選べる状態にする。
詳細な実装ガイドは references/ ディレクトリを参照。各ファイルは「概念 → 汎用パターン → 最小コード例 → 落とし穴」の順で構成している。
| ファイル | カバー内容 |
|---------|-----------|
| FASTIFY-FUNDAMENTALS.md | インスタンス化・ルーティング・request/reply・ライフサイクル/フック・プラグイン & encapsulation・decorators・スキーマ検証 & シリアライゼーション(AJV)・Pino ロギング・エラーハンドリング |
| NODE-RUNTIME-INTERNALS.md | イベントループのフェーズ詳細・libuv・ストリーム & バッファ・clustering / worker threads・Blocking the Event Loop 回避・process stdio |
| REST-API-DESIGN.md | HTTP メソッド・RESTful ルート設計・CRUD API レイアウト・リソース設計の実装レシピ |
| DATA-PERSISTENCE-PATTERNS.md | Mongoose / Sequelize / SQLite3 / Redis 接続パターン・SQLite vs PostgreSQL 選択基準・AskUserQuestion: 永続化レイヤ選択 |
| AUTHENTICATION-FLOWS.md | セッション/Cookie・bcrypt / node:crypto ハッシュ・JWT 認証・AskUserQuestion: 認証方式選択 |
| SERVER-SIDE-RENDERING.md | EJS / Handlebars SSR・@fastify/view・静的アセット配信・フォームレンダリング・AskUserQuestion: テンプレートエンジン |
| MESSAGING-AND-QUEUES.md | インメモリキュー・Redis キュー・RabbitMQ/amqplib・AskUserQuestion: キュー技術選択 |
| CLI-TOOLS.md | process 標準入出力・引数処理・promisify・外部パッケージ利用・CSV 変換 |
| EXTERNAL-DATA-INTEGRATION.md | native fetch・フィード取得と集約・スクレイピング(cheerio / Puppeteer)・文字列処理と感情分析 |
| SERVICE-INTEGRATIONS.md | メール(nodemailer)・タスクスケジューラ・生成 AI API 統合の実装面(詳細は ai:integrating-ai-web-apps へ) |
| PROJECT-SCAFFOLDING.md | npm init・スケール別ディレクトリ構成・ESM / top-level await / node --watch / native fetch・Yarn vs npm |
| QUALITY-CHECKLIST.md | fastify.inject ルートテスト・graceful shutdown・環境設定・エラーハンドリング・セキュリティ基本 |
以下は本スキルの対象外。適切なスキルへ誘導する:
| 対象外テーマ | 参照先スキル |
|------------|-------------|
| Express / NestJS バックエンド | developing-fullstack-javascript |
| React / Next.js フロントエンド | developing-fullstack-javascript |
| CI/CD・デプロイメント・コンテナ本番設定 | cloud:practicing-devops |
| REST / GraphQL / gRPC のスタイル選定 | choosing-api-styles |
| HTTP プロトコル設計・バージョニング・API テスト戦略 | developing-web-apis |
| DB スキーマ設計・SQL チューニング | lang:developing-databases |
| プロンプトエンジニアリング・LLM アプリアーキテクチャ | ai:integrating-ai-web-apps |
| JavaScript 言語基礎(クロージャ・プロトタイプ等) | developing-fullstack-javascript |
tools
FastAPI (Python) web API development guide covering fundamentals (routing, path/query params, Pydantic models, request/response, error handling), data persistence (SQLAlchemy, SQLModel, async DB, MongoDB, CRUD, Alembic migrations), dependency injection (Depends, dependency_overrides, scopes/lifespan), auth & security (OAuth2, JWT, CORS), async & concurrency (async/await, Starlette, BackgroundTasks, WebSocket, SSE/streaming), testing (TestClient, pytest, httpx, mocking), production deployment & scaling (uvicorn/gunicorn, Docker, optimization), generative-AI services (model serving, streaming, concurrency), and microservice/GraphQL/OpenAPI patterns. MUST load when fastapi is in pyproject.toml/requirements.txt or .py files import fastapi. For Python language/tooling fundamentals (uv/ruff/mypy, packaging, non-FastAPI patterns), use lang:developing-python. For REST/HTTP-spec design, versioning, and API test strategy, use developing-web-apis. For Node.js/Fastify backend services, use building-nodejs-services.
development
studying(スタディング, member.studying.jp)のコースレッスン一覧URLから、配下の「スマート問題集」 「セレクト過去問集(学科試験対策・実技試験対策)」の全問題(問題文・選択肢・正解・解説)を科目単位で 取得し、1科目1JSONファイルに保存する。出力は creating-flashcards スキルへ渡して科目ごとに Anki フラッシュカード化できる。 Use when studying のコースレッスン一覧URL(https://member.studying.jp/course/id/<course_id>/ 形式) を渡され「問題を全部保存したい」「Anki カードにしたい」等と言われたとき。 補足トリガー: studying, スタディング, 資格試験, スマート問題集, セレクト過去問集, 問題集, JSON 保存, Anki 連携。 ブラウザ操作自体の汎用ガイドは web:automating-browser、E2E テストは web:testing-e2e-with-playwright を使う。本スキルは studying 専用の収集ワークフロー + bundled script(scripts/collect-studying.sh) +ログイン認証を提供する。
development
Whizlabs のコース practice test 一覧URLから、配下の全クイズ(Free Test・Practice Test 1〜N 等)を practice mode で巡回し、各問題(問題文・選択肢・正解・解説・参考資料)を取得して 1 クイズ 1 JSON ファイルに 保存する。出力は creating-flashcards スキルへ渡してクイズごとに Anki フラッシュカード化できる。 Use when Whizlabs のコースURL(/learn/course/<slug>/<course-id>/pt 形式)を渡され 「問題を全部保存したい」「Anki カードにしたい」等と言われたとき。 補足トリガー: whizlabs, ホイズラボ, 資格試験, 問題集, practice test, quiz 収集, JSON 保存, Anki 連携。 ブラウザ操作自体の汎用ガイドは web:automating-browser、E2E テストは web:testing-e2e-with-playwright を使う。 本スキルは Whizlabs 専用の収集ワークフロー + bundled script(scripts/collect-whizlabs.sh)+ ログイン認証(agent-browser Auth Vault)を提供する。
development
Guides production Flutter app development with Dart targeting iOS, Android, web, and desktop from a single codebase, including project setup, the widget system (Stateless/Stateful, Material and Cupertino), layout, theming and animation, state management (setState, Provider, Riverpod, BLoC/Cubit, Redux, GetX), navigation and routing (Navigator, go_router, auto_route), networking and backends (http, dio, REST, Firebase, GraphQL), local persistence, responsive multi-platform design, architecture patterns (Clean Architecture, BLoC, MVVM), the pub.dev package ecosystem, widget and integration testing, performance optimization, and build and store release. REQUIRED when creating, implementing, modifying, testing, or shipping a Flutter app, or when pubspec.yaml lists the flutter SDK. For the Dart language itself (types, null safety, OOP, async, collections), use developing-dart. For native iOS/iPadOS apps in Swift/SwiftUI, use developing-ios-apps. For Apple HIG UI/UX decisions, use applying-apple-hig.