Back
📜Rulecursor

Full-Stack API Error Handler

A Copilot/Cursor rule for implementing consistent error handling across full-stack TypeScript applications. Covers HTTP errors, validation, and logging.

by TypeScriptGuru·6 days ago·
error handlingtypescriptapifull-stackbest practices
# Error Handling Rule

When implementing API endpoints, ALWAYS follow this error handling pattern:

## Server-side (Next.js Route Handlers / Express)

```typescript
import { AppError, ValidationError, NotFoundError, AuthError } from '@/lib/errors';

// Use typed error classes
try {
  const data = await operation();
  return Response.json({ data });
} catch (error) {
  if (error instanceof ValidationError) {
    return Response.json({ error: error.message, details: error.fields }, { status: 400 });
  }
  if (error instanceof NotFoundError) {
    return Response.json({ error: error.message }, { status: 404 });
  }
  if (error instanceof AuthError) {
    return Response.json({ error: 'Unauthorized' }, { status: 401 });
  }
  // Log unexpected errors, don't expose internals
  console.error('Unexpected error:', error);
  return Response.json({ error: 'Internal server error' }, { status: 500 });
}
```

## Client-side

```typescript
// Always handle loading, error, and success states
const [state, setState] = useState<{ data: T | null; error: string | null; loading: boolean }>({
  data: null, error: null, loading: false
});

// Use try/catch with fetch
try {
  setState(s => ({ ...s, loading: true, error: null }));
  const res = await fetch(url);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  const data = await res.json();
  setState({ data, error: null, loading: false });
} catch (err) {
  setState({ data: null, error: err instanceof Error ? err.message : 'Unknown error', loading: false });
}
```

NEVER: swallow errors silently, expose stack traces to clients, use any for error types.