Prisma:TypeScript向け次世代ORM
データベース操作を型安全かつ直感的に実現するPrismaは、従来のORMとは異なるアプローチを採用しています。スキーマ定義ファイル(schema.prisma)を基に、自動的に型付きクライアントを生成し、TypeScriptの開発体験を大幅に向上させます。
// prisma/schema.prisma
model User {
id Int @id @default(autoincrement())
email String @unique
profile Profile? @relation(fields: [profileId], references: [id])
createdAt DateTime @default(now())
}
model Profile {
id Int @id @default(autoincrement())
bio String?
userId Int @unique
user User @relation(fields: [userId], references: [id])
}
クライアントを使用してデータを操作する際は、メソッドチェーンと型推論が活かされます:
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
// ユーザー作成(型チェック対応)
const user = await prisma.user.create({
data: {
email: 'test@example.com',
profile: {
create: { bio: 'Developer' }
}
}
})
// 関連データ付きで取得
const usersWithProfiles = await prisma.user.findMany({
include: { profile: true }
})
マイグレーションは自動生成され、データベースの変更履歴を管理しやすくなります。ただし、カスタムSQLや複雑なJOINは制限される可能性がある点に注意が必要です。
Day.js:軽量で高速な日付処理ライブラリ
Moment.jsの後継として登場したDay.jsは、API互換性を保ちつつ、バンドルサイズを1/10以下に削減しました。モジュールのインポートもESM対応で、Tree-shakingが可能です。
import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime'
import 'dayjs/locale/ja'
dayjs.extend(relativeTime)
dayjs.locale('ja')
const now = dayjs()
const past = dayjs().subtract(2, 'hours')
console.log(past.fromNow()) // "2時間前"
console.log(now.format('YYYY年MM月DD日 HH:mm')) // "2024年04月15日 14:30"
プラグインシステムにより、ローカライズやカスタムフォーマットも柔軟に拡張できます。パフォーマンス面でも、単純な日付操作ではMoment.jsの約20倍速く動作します。
Cypress:ブラウザ内エンドツーエンドテスト
Cypressは、テストコードがブラウザ内で直接実行されるため、リアルタイムなデバッグが可能です。タイムアウトや待機処理の自動管理により、非同期処理のテストが簡素化されています。
describe('ユーザー認証', () => {
it('ログインに成功する', () => {
cy.visit('/login')
cy.get('[data-testid="email"]').type('user@example.com')
cy.get('[data-testid="password"]').type('password123')
cy.get('[data-testid="submit-btn"]').click()
// ログイン後のリダイレクトを待機
cy.url().should('include', '/dashboard')
cy.get('[data-testid="user-name"]').should('have.text', 'User Name')
})
it('APIレスポンスをモックする', () => {
cy.intercept('GET', '/api/profile', {
fixture: 'user-profile.json'
}).as('getUserProfile')
cy.visit('/profile')
cy.wait('@getUserProfile')
cy.get('[data-testid="profile-email"]').should('be.visible')
})
})
テスト実行中にスクリーンショットや動画記録が自動生成され、CI/CDパイプラインへの統合も容易です。
Winston:多様な出力先に対応するログ管理
Winstonは、ログの出力先・フォーマット・レベルを柔軟に制御できる汎用ロガーです。ファイル出力には日付別ローテーションを組み合わせることで、運用負荷を軽減できます。
const { createLogger, transports, format } = require('winston')
const { combine, timestamp, json } = format
const logger = createLogger({
level: 'info',
format: combine(timestamp(), json()),
transports: [
new transports.Console(),
new transports.DailyRotateFile({
filename: 'logs/application-%DATE%.log',
datePattern: 'YYYY-MM-DD',
maxFiles: '14d'
})
]
})
logger.info('アプリケーション起動')
logger.error('DB接続失敗', { stack: error.stack })
カスタムフォーマッターやフィルタリング機能を活用すれば、環境ごとのログ出力を最適化できます。
express-rate-limit:リクエスト制限でサーバーを守る
DDoSやボット攻撃への対策として、IPごとのリクエスト頻度を制限するミドルウェアです。Redisをバックエンドにすることで、クラスタ環境でも有効に機能します。
const rateLimit = require('express-rate-limit')
const apiLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
keyGenerator: (req) => req.ip,
handler: (req, res) => {
res.status(429).json({ error: 'リクエストが多すぎます' })
}
})
app.use('/api/', apiLimiter)
// 特定ルートにカスタム制限を適用
app.post('/login', rateLimit({ windowMs: 3600000, max: 5 }), loginHandler)
カスタムキー生成により、ユーザーIDやJWTトークンに基づく制限も可能で、より細かなセキュリティ制御が実現できます。
semver:バージョン管理の標準化
SemVer(Semantic Versioning)に基づくバージョン比較・操作を支援するライブラリです。パッケージ依存関係の自動解決や、互換性判定に不可欠です。
const semver = require('semver')
// バージョン範囲の検証
semver.satisfies('1.2.3', '^1.2.0') // true
semver.satisfies('2.0.0', '~1.0.0') // false
// バージョンの自動インクリメント
semver.inc('1.2.3-beta.1', 'prerelease') // "1.2.3-beta.2"
semver.inc('1.2.3', 'major') // "2.0.0"
// バージョン比較
semver.gt('1.10.0', '1.2.3') // true
semver.lt('0.9.9', '1.0.0') // true
npmやyarnの依存解決と連携して、安定した依存関係管理を実現します。
Superagent:シンプルで強力なHTTPクライアント
チェーン呼び出しとPromise対応で、複雑なAPI呼び出しを読みやすく記述できます。Node.jsとブラウザ両方で同じコードが動作します。
const request = require('superagent')
const response = await request
.get('https://api.example.com/items')
.set('Authorization', `Bearer ${token}`)
.query({ page: 1, limit: 10 })
.timeout({ response: 5000, deadline: 10000 })
const items = response.body
const etag = response.headers.etag
ファイルアップロードやmultipart/form-dataの処理もネイティブでサポートされており、軽量なHTTPクライアントとして優れています。
Axios-retry:ネットワーク不安定時の自動再試行
Axiosに自動再試行機能を追加する軽量プラグインです。指数バックオフやステータスコードによる条件付き再試行が可能です。
import axios from 'axios'
import axiosRetry from 'axios-retry'
const client = axios.create({
baseURL: 'https://api.example.com',
timeout: 5000
})
axiosRetry(client, {
retries: 3,
retryDelay: (retryCount) => retryCount * 1000 + Math.random() * 1000,
retryCondition: (error) => {
return error.response?.status >= 500 || error.code === 'ECONNABORTED'
},
shouldResetTimeout: true
})
// 再試行が3回失敗しても、最終的にエラーがthrowされる
client.get('/data').catch(err => console.error('リトライ失敗:', err))
ネットワークの一時的な不安定を自動回復させ、ユーザー体験の信頼性を向上させます。
js-yaml:YAML構成ファイルの安全な処理
JavaScriptオブジェクトとYAML形式の相互変換を安全に行うライブラリです。safeLoadとsafeDumpは、悪意あるコードの実行を防ぐために推奨されます。
const yaml = require('js-yaml')
const config = yaml.safeLoad(`
database:
host: localhost
port: 5432
ssl: true
features:
- auth
- analytics
- cache
`)
console.log(config.database.host) // "localhost"
console.log(config.features[1]) // "analytics"
const yamlOutput = yaml.safeDump({
app: 'my-service',
version: '1.2.0',
env: 'production'
})
// 出力:
// app: my-service
// version: 1.2.0
// env: production
構造の検証には、YAMLスキーマ定義(例:ajv)と組み合わせるのが望ましいです。
mime-types:ファイルのMIMEタイプを正確に判定
拡張子やバイナリヘッダーからMIMEタイプを推定するための、信頼性の高いデータベースを提供します。
const mime = require('mime-types')
// 拡張子からMIMEタイプを取得
mime.lookup('image.png') // "image/png"
mime.lookup('document.pdf') // "application/pdf"
// バッファからMIMEタイプを推定
const buffer = Buffer.from('%PDF-1.4')
mime.lookup(buffer) // "application/pdf"
// MIMEタイプから拡張子リストを取得
mime.extensions('text/css') // ["css"]
mime.extensions('image/svg+xml') // ["svg"]
// 未知の拡張子のデフォルト値
mime.lookup('file.xyz') // false
mime.lookup('file.xyz', 'text/plain') // "text/plain"
ファイルアップロード処理や、CDN配信のContent-Type設定に不可欠なツールです。