Designing Error Boundaries with Claude Code: From Frontend to API
Designing Error Boundaries using Claude Code. From Frontend to API. Includes practical code examples.
エラーバウンダリとは
エラーバウンダリは、アプリケーションの一部でエラーが発生しても全体がクラッシュしないようにする防御的な設計パターンです。Claude Codeを使えば、フロントエンドとバックエンドの両方で一貫したエラー処理を設計できます。
React Error Boundary
import { Component, ErrorInfo, ReactNode } from "react";
interface ErrorBoundaryProps {
children: ReactNode;
fallback?: ReactNode;
onError?: (error: Error, errorInfo: ErrorInfo) => void;
}
interface ErrorBoundaryState {
hasError: boolean;
error: Error | null;
}
class ErrorBoundary extends Component<
ErrorBoundaryProps,
ErrorBoundaryState
> {
constructor(props: ErrorBoundaryProps) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error: Error): ErrorBoundaryState {
return { hasError: true, error };
}
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
console.error("Error caught by boundary:", error, errorInfo);
this.props.onError?.(error, errorInfo);
// Send to error monitoring service
reportError(error, {
componentStack: errorInfo.componentStack,
});
}
render() {
if (this.state.hasError) {
return (
this.props.fallback || (
<div className="error-fallback">
<h2>エラーが発生しました</h2>
<p>{this.state.error?.message}</p>
<button onClick={() => this.setState({ hasError: false, error: null })}>
再試行
</button>
</div>
)
);
}
return this.props.children;
}
}
関数コンポーネント向けフック
import { useCallback, useState } from "react";
function useErrorHandler() {
const [error, setError] = useState<Error | null>(null);
if (error) {
throw error; // 親のError Boundaryでキャッチ
}
const handleError = useCallback((err: unknown) => {
if (err instanceof Error) {
setError(err);
} else {
setError(new Error(String(err)));
}
}, []);
const withErrorHandling = useCallback(
<T,>(fn: () => Promise<T>) => {
return async () => {
try {
return await fn();
} catch (err) {
handleError(err);
return undefined;
}
};
},
[handleError]
);
return { handleError, withErrorHandling };
}
API エラーレスポンスの標準化
// エラーコード定義
enum ErrorCode {
VALIDATION_ERROR = "VALIDATION_ERROR",
NOT_FOUND = "NOT_FOUND",
UNAUTHORIZED = "UNAUTHORIZED",
FORBIDDEN = "FORBIDDEN",
CONFLICT = "CONFLICT",
INTERNAL_ERROR = "INTERNAL_ERROR",
RATE_LIMITED = "RATE_LIMITED",
}
interface ApiError {
code: ErrorCode;
message: string;
details?: Record<string, unknown>;
requestId: string;
timestamp: string;
}
class AppError extends Error {
constructor(
public code: ErrorCode,
message: string,
public statusCode: number,
public details?: Record<string, unknown>
) {
super(message);
this.name = "AppError";
}
static notFound(resource: string) {
return new AppError(
ErrorCode.NOT_FOUND,
`${resource} not found`,
404
);
}
static validation(details: Record<string, string>) {
return new AppError(
ErrorCode.VALIDATION_ERROR,
"Validation failed",
400,
details
);
}
static unauthorized(message = "Authentication required") {
return new AppError(ErrorCode.UNAUTHORIZED, message, 401);
}
}
グローバルエラーハンドラー
import { v4 as uuidv4 } from "uuid";
function globalErrorHandler(
err: Error,
req: express.Request,
res: express.Response,
next: express.NextFunction
) {
const requestId = uuidv4();
if (err instanceof AppError) {
// 業務エラー
return res.status(err.statusCode).json({
code: err.code,
message: err.message,
details: err.details,
requestId,
timestamp: new Date().toISOString(),
});
}
// 予期しないエラー
console.error(`[${requestId}] Unexpected error:`, err);
res.status(500).json({
code: ErrorCode.INTERNAL_ERROR,
message: "An unexpected error occurred",
requestId,
timestamp: new Date().toISOString(),
});
}
// 登録順序が重要:ルーターの後に配置
app.use(globalErrorHandler);
非同期エラーのキャッチ
// asyncHandler ラッパー
function asyncHandler(
fn: (
req: express.Request,
res: express.Response,
next: express.NextFunction
) => Promise<void>
) {
return (
req: express.Request,
res: express.Response,
next: express.NextFunction
) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
}
// Usage example
router.get(
"/users/:id",
asyncHandler(async (req, res) => {
const user = await prisma.user.findUnique({
where: { id: req.params.id },
});
if (!user) {
throw AppError.notFound("User");
}
res.json({ data: user });
})
);
階層的エラーバウンダリ
React側では複数のError Boundaryを階層的に配置します。エラー処理の設計をClaude Codeに依頼する際の参考にしてください。プロンプトの書き方は効果的なプロンプト5つのTips、コード品質の改善にはリファクタリング自動化も役立ちます。
function App() {
return (
<ErrorBoundary fallback={<FullPageError />}>
<Header />
<ErrorBoundary fallback={<SidebarFallback />}>
<Sidebar />
</ErrorBoundary>
<ErrorBoundary fallback={<ContentFallback />}>
<MainContent />
</ErrorBoundary>
</ErrorBoundary>
);
}
エラーハンドリングの設計原則についてはMDN Web Docs: Error handlingが参考になります。Claude Codeの詳細は公式ドキュメントを確認してください。
Zusammenfassung
エラーバウンダリはユーザー体験を損なわないための重要な設計パターンです。Claude Codeを使えば、フロントエンドからAPIまで一貫したエラー処理を効率的に実装できます。
Related Posts
Claude Code Hooks meistern: Auto-Formatierung, Auto-Tests und mehr
Erfahren Sie, wie Sie Auto-Formatierung und Auto-Tests mit Claude Code Hooks einrichten. Inklusive praktischer Konfigurationsbeispiele und realer Anwendungsfälle.
Claude Code MCP-Server: Einrichtung und praktische Anwendungsfälle
Ein umfassender Leitfaden zu den MCP-Server-Funktionen von Claude Code. Erfahren Sie, wie Sie externe Tools anbinden, Server konfigurieren, und entdecken Sie praxisnahe Integrationsbeispiele.
Der komplette Leitfaden zum Schreiben von CLAUDE.md: Best Practices für die Projektkonfiguration
Ein umfassender Leitfaden zum Schreiben effektiver CLAUDE.md-Dateien. Erfahren Sie, wie Sie Ihren Tech-Stack, Konventionen und Projektstruktur kommunizieren, um die Ausgabequalität von Claude Code zu maximieren.