express-typescript
Express.jsとTypeScriptを用いた堅牢なAPI構築のためのガイドラインを提供するスキルで、ミドルウェアのパターン設計、ルーティング構成、セキュリティのベストプラクティスを網羅します。APIの設計・実装時に活用することで、保守性と安全性の高いコードベースを実現できます。
description の原文を見る
Guidelines for building robust APIs with Express.js and TypeScript, covering middleware patterns, routing, and security best practices
SKILL.md 本文
Express TypeScript Development
Express.js と TypeScript 開発のエキスパートで、スケーラブルで保守性の高い API を構築する深い知識を有しています。
TypeScript 一般ガイドライン
基本原則
- すべてのコードとドキュメントは英語を使用する
- 常に変数と関数(パラメータと戻り値)の型を宣言する
any型の使用を避け、必要な型を作成する- JSDoc を使用してパブリッククラスとメソッドをドキュメント化する
- 簡潔で保守性が高く、技術的に正確なコードを書く
- 関数型とデクラレーティブプログラミングパターンを使用し、可能な限りクラスを避ける
- DRY 原則に従うため、反復処理とモジュール化を優先する
命名規則
- 型とインターフェースには PascalCase を使用する
- 変数、関数、メソッドには camelCase を使用する
- ファイルとディレクトリ名には kebab-case を使用する
- 環境変数には UPPERCASE を使用する
- 補助動詞を含む説明的な変数名を使用する:
isLoading,hasError,canDelete - 各関数を動詞で開始する
関数
- 単一の目的を持つ短い関数を書く
- ミドルウェアとハンドラーには矢印関数を使用する
- コードベース全体で async/await を一貫して使用する
- 複数のパラメータには RO-RO パターンを使用する
型とインターフェース
- オブジェクト形状にはタイプより インターフェースを優先する
- enum を避け、マップまたは const オブジェクトを使用する
- Zod を使用してランタイム検証と推論型を行う
- 不変プロパティには
readonlyを使用する
Express 固有ガイドライン
プロジェクト構造
src/
routes/
{resource}/
index.ts
controller.ts
validators.ts
middleware/
auth.ts
errorHandler.ts
requestLogger.ts
validateRequest.ts
services/
{domain}Service.ts
models/
{entity}.ts
types/
express.d.ts
index.ts
utils/
config/
app.ts
server.ts
アプリケーション設定
import express, { Express } from 'express';
import helmet from 'helmet';
import cors from 'cors';
import { errorHandler } from './middleware/errorHandler';
import { requestLogger } from './middleware/requestLogger';
import routes from './routes';
const createApp = (): Express => {
const app = express();
// Security middleware
app.use(helmet());
app.use(cors());
// Body parsing
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Request logging
app.use(requestLogger);
// Routes
app.use('/api', routes);
// Error handling (must be last)
app.use(errorHandler);
return app;
};
export default createApp;
ミドルウェアパターン
- クロスカッティングコンサーンのためにミドルウェアを使用する
- 実行順に合わせてミドルウェアを連鎖させる
- 専用のエラーミドルウェアでエラーを処理する
import { Request, Response, NextFunction } from 'express';
// Request logging middleware
const requestLogger = (req: Request, res: Response, next: NextFunction): void => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
console.log(`${req.method} ${req.path} ${res.statusCode} ${duration}ms`);
});
next();
};
// Authentication middleware
const authenticate = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
try {
const token = req.headers.authorization?.split(' ')[1];
if (!token) {
res.status(401).json({ error: 'No token provided' });
return;
}
const user = await verifyToken(token);
req.user = user;
next();
} catch (error) {
res.status(401).json({ error: 'Invalid token' });
}
};
ルーティング
- リソースごとにルートを整理する
- モジュール化されたルート定義のために Router を使用する
- 適切なレベルでミドルウェアを適用する
import { Router } from 'express';
import { authenticate } from '../middleware/auth';
import { validateRequest } from '../middleware/validateRequest';
import { createUserSchema, updateUserSchema } from './validators';
import * as controller from './controller';
const router = Router();
router.get('/', controller.listUsers);
router.get('/:id', controller.getUser);
router.post('/', validateRequest(createUserSchema), controller.createUser);
router.put('/:id', authenticate, validateRequest(updateUserSchema), controller.updateUser);
router.delete('/:id', authenticate, controller.deleteUser);
export default router;
リクエスト検証
- すべてのインカミングリクエストを検証する
- スキーマ定義と検証に Zod を使用する
- 再利用可能な検証ミドルウェアを作成する
import { z } from 'zod';
import { Request, Response, NextFunction } from 'express';
const createUserSchema = z.object({
body: z.object({
name: z.string().min(1),
email: z.string().email(),
password: z.string().min(8),
}),
});
const validateRequest = (schema: z.ZodSchema) => {
return async (req: Request, res: Response, next: NextFunction): Promise<void> => {
try {
await schema.parseAsync({
body: req.body,
query: req.query,
params: req.params,
});
next();
} catch (error) {
if (error instanceof z.ZodError) {
res.status(400).json({
error: 'Validation failed',
details: error.errors,
});
return;
}
next(error);
}
};
};
エラーハンドリング
- カスタムエラークラスを作成する
- 集中化されたエラーハンドラーミドルウェアを使用する
- 一貫したエラーレスポンスを返す
class AppError extends Error {
constructor(
public statusCode: number,
public message: string,
public code: string = 'INTERNAL_ERROR'
) {
super(message);
this.name = 'AppError';
}
}
class NotFoundError extends AppError {
constructor(resource: string) {
super(404, `${resource} not found`, 'NOT_FOUND');
}
}
// Error handler middleware
const errorHandler = (err: Error, req: Request, res: Response, next: NextFunction): void => {
if (err instanceof AppError) {
res.status(err.statusCode).json({
error: err.code,
message: err.message,
});
return;
}
console.error(err);
res.status(500).json({
error: 'INTERNAL_ERROR',
message: 'An unexpected error occurred',
});
};
TypeScript 拡張
Express 型をカスタムプロパティのために拡張する:
// types/express.d.ts
import { User } from '../models/User';
declare global {
namespace Express {
interface Request {
user?: User;
requestId?: string;
}
}
}
セキュリティベストプラクティス
- セキュリティヘッダーのために helmet を使用する
- レート制限を実装する
- ユーザー入力をサニタイズする
- 本番環境では HTTPS を使用する
- CORS を適切に実装する
import helmet from 'helmet';
import rateLimit from 'express-rate-limit';
app.use(helmet());
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
});
app.use('/api', limiter);
テスト
- 統合テストに Jest と supertest を使用する
- ミドルウェアを単独でテストする
- 外部の依存関係をモックする
import request from 'supertest';
import createApp from '../app';
describe('Users API', () => {
const app = createApp();
it('should create a user', async () => {
const response = await request(app)
.post('/api/users')
.send({ name: 'John', email: 'john@example.com', password: 'password123' })
.expect(201);
expect(response.body).toHaveProperty('id');
expect(response.body.name).toBe('John');
});
});
ライセンス: Apache-2.0(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- mindrally
- リポジトリ
- mindrally/skills
- ライセンス
- Apache-2.0
- 最終更新
- 不明
Source: https://github.com/mindrally/skills / ライセンス: Apache-2.0
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。