Advanced

Designing Error Boundaries with Claude Code: From Frontend to API

Designing Error Boundaries using Claude Code. From Frontend to API. Includes practical code examples.

errorバウンダリ

errorバウンダリ 、aplikasi 一部 error 発生 juga 全体 クラッシュし tidak agar 防御的な設計pola.Claude Code 使えば、frontend dan backend 両方 一貫 errorpemrosesan 設計 bisa dilakukan.

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;
  }
}

fungsikomponen向けフック

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 errorresponse

// errorコードdefinisi
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);
  }
}

Global Error Handler

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) {
    // 業務error
    return res.status(err.statusCode).json({
      code: err.code,
      message: err.message,
      details: err.details,
      requestId,
      timestamp: new Date().toISOString(),
    });
  }

  // 予期し tidakerror
  console.error(`[${requestId}] Unexpected error:`, err);

  res.status(500).json({
    code: ErrorCode.INTERNAL_ERROR,
    message: "An unexpected error occurred",
    requestId,
    timestamp: new Date().toISOString(),
  });
}

// registrasi順序 penting:ルーター 後 penempatan
app.use(globalErrorHandler);

Menangkap Error Async

// 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 });
  })
);

階層的errorバウンダリ

React側 複数 Error Boundary 階層的 penempatan.errorpemrosesan 設計 Claude Code 依頼 際 参考 .プロンプト 書き方 効果的なプロンプト5つ Tips、コード品質 peningkatan refactoringotomatisasi juga 役立ち.

function App() {
  return (
    <ErrorBoundary fallback={<FullPageError />}>
      <Header />
      <ErrorBoundary fallback={<SidebarFallback />}>
        <Sidebar />
      </ErrorBoundary>
      <ErrorBoundary fallback={<ContentFallback />}>
        <MainContent />
      </ErrorBoundary>
    </ErrorBoundary>
  );
}

errorハンドリング 設計原則 mengenai MDN Web Docs: Error handling 参考 なり.Claude Code 詳細 公式dokumen konfirmasi .

Summary

errorバウンダリ pengguna体験 損なわ tidak untuk pentingな設計pola.Claude Code 使えば、frontend dari APIま 一貫 errorpemrosesan efisien implementasi bisa dilakukan.

#Claude Code #error handling #React #API design #TypeScript