backend-patterns
SKILL.md
backend-patterns - バックエンドパターン集
バックエンドコード規約とパターン。
使い方
新しいAPIルートを作る時、このスキルを参照
1. APIルート構造
認証パターン(Next.js例)
// 認証ミドルウェアを使用
import { withAuth } from '@/lib/middleware/with-auth';
import { apiSuccess, apiError } from '@/lib/api-response';
export const GET = withAuth(async ({ userId, request }) => {
const data = await repository.findByUserId(userId);
return apiSuccess({ data });
});
export const POST = withAuth(async ({ userId, request }) => {
const body = await request.json();
// バリデーション & 処理
return apiSuccess({ created: result });
});
Express.js例
import { Router } from 'express';
import { authenticate } from '@/middleware/auth';
import { validate } from '@/middleware/validate';
const router = Router();
router.get('/', authenticate, async (req, res) => {
const data = await repository.findByUserId(req.user.id);
res.json({ success: true, data });
});
router.post('/', authenticate, validate(createSchema), async (req, res) => {
const result = await repository.create(req.body);
res.status(201).json({ success: true, data: result });
});
2. レスポンス形式
統一レスポンス
// lib/api-response.ts
export function apiSuccess<T>(data: T, options?: { status?: number }) {
return Response.json(
{ success: true, data, timestamp: new Date().toISOString() },
{ status: options?.status ?? 200 }
);
}
export function apiError(message: string, options?: { status?: number; code?: string }) {
return Response.json(
{ success: false, error: message, code: options?.code, timestamp: new Date().toISOString() },
{ status: options?.status ?? 400 }
);
}
レスポンス形式
// 成功
{
"success": true,
"data": { ... },
"timestamp": "2026-01-19T12:00:00.000Z"
}
// エラー
{
"success": false,
"error": "Error message",
"code": "ERROR_CODE",
"timestamp": "2026-01-19T12:00:00.000Z"
}
3. バリデーション
Zodスキーマ
import { z } from 'zod';
const createUserSchema = z.object({
email: z.string().email('Invalid email'),
name: z.string().min(1, 'Name is required').max(100),
role: z.enum(['user', 'admin']).optional(),
});
// APIルートで使用
const validation = createUserSchema.safeParse(body);
if (!validation.success) {
return apiError('Invalid input', { status: 400 });
}
const { email, name, role } = validation.data;
共通スキーマ
// UUID
const idSchema = z.string().uuid('Invalid ID format');
// ページネーション
const paginationSchema = z.object({
page: z.coerce.number().min(1).default(1),
limit: z.coerce.number().min(1).max(100).default(20),
});
4. Repository パターン
基本構造
// lib/repositories/user.repository.ts
import { db } from '@/db';
import { users } from '@/db/schema';
import { eq } from 'drizzle-orm';
export interface CreateUserInput {
email: string;
name: string;
}
export const userRepository = {
async create(input: CreateUserInput) {
const [result] = await db.insert(users).values(input).returning();
return result;
},
async findById(id: string) {
const [result] = await db
.select()
.from(users)
.where(eq(users.id, id))
.limit(1);
return result ?? null;
},
async findByEmail(email: string) {
const [result] = await db
.select()
.from(users)
.where(eq(users.email, email))
.limit(1);
return result ?? null;
},
async update(id: string, input: Partial<CreateUserInput>) {
const [result] = await db
.update(users)
.set({ ...input, updatedAt: new Date() })
.where(eq(users.id, id))
.returning();
return result;
},
async delete(id: string) {
await db.delete(users).where(eq(users.id, id));
},
};
5. エラーハンドリング
export const POST = withAuth(async ({ userId, request }) => {
try {
const body = await request.json();
const result = await repository.create(body);
return apiSuccess({ result });
} catch (error) {
console.error('[API] Error:', error);
if (error instanceof z.ZodError) {
return apiError('Validation failed', { status: 400 });
}
if (error instanceof Error && error.message.includes('unique')) {
return apiError('Already exists', { status: 409 });
}
return apiError('Internal server error', { status: 500 });
}
});
6. チェックリスト
新しいAPIルート作成時:
- 認証ミドルウェア適用
- リクエストバリデーション(Zod)
- 統一レスポンス形式使用
- エラーハンドリング(try-catch)
- 認可チェック(リソース所有者確認)
- ログ出力
7. アンチパターン
// ❌ 認証なし
export async function GET(request: Request) {
const data = await db.select().from(users);
return Response.json(data);
}
// ❌ バリデーションなし
const { email } = await request.json();
await db.insert(users).values({ email });
// ❌ エラー握りつぶし
try {
await riskyOperation();
} catch (e) {
// 何もしない
}
Weekly Installs
50
Repository
kimny1143/claud…templateFirst Seen
Feb 9, 2026
Security Audits
Installed on
claude-code47
gemini-cli18
opencode17
github-copilot17
codex17
kimi-cli16