# Error Handling Quick Reference

## Import

```typescript
import {
  NotFoundError,
  ValidationError,
  UnauthorizedError,
  BadRequestError,
  ConflictError,
  ForbiddenError,
  InternalServerError,
  GlobalExceptionFilter,
  createErrorMiddleware,
  notFoundMiddleware,
} from '@erp-suite/core';
```

## Error Classes

| Class | Status | Usage |
|-------|--------|-------|
| `BadRequestError(msg, details?)` | 400 | Invalid request |
| `UnauthorizedError(msg, details?)` | 401 | No/invalid auth |
| `ForbiddenError(msg, details?)` | 403 | No permission |
| `NotFoundError(msg, details?)` | 404 | Not found |
| `ConflictError(msg, details?)` | 409 | Duplicate/conflict |
| `ValidationError(msg, details?)` | 422 | Validation failed |
| `InternalServerError(msg, details?)` | 500 | Server error |

## NestJS Setup

### main.ts
```typescript
import { GlobalExceptionFilter } from '@erp-suite/core';

app.useGlobalFilters(new GlobalExceptionFilter());
```

### Usage
```typescript
throw new NotFoundError('User not found', { userId: id });
```

## Express Setup

### index.ts
```typescript
import { createErrorMiddleware, notFoundMiddleware } from '@erp-suite/core';

// Routes
app.use('/api', routes);

// 404 handler
app.use(notFoundMiddleware);

// Error handler (MUST BE LAST)
app.use(createErrorMiddleware());
```

### Async Handler
```typescript
const asyncHandler = (fn) => (req, res, next) =>
  Promise.resolve(fn(req, res, next)).catch(next);

app.get('/users/:id', asyncHandler(async (req, res) => {
  const user = await findUser(req.params.id);
  res.json(user);
}));
```

### Usage
```typescript
throw new NotFoundError('User not found', { userId: id });
```

## Common Patterns

### Not Found
```typescript
if (!user) {
  throw new NotFoundError('User not found', { userId: id });
}
```

### Validation
```typescript
throw new ValidationError('Validation failed', {
  errors: [
    { field: 'email', message: 'Invalid format' },
    { field: 'age', message: 'Must be 18+' }
  ]
});
```

### Unauthorized
```typescript
if (!token) {
  throw new UnauthorizedError('Token required');
}
```

### Conflict
```typescript
if (existingUser) {
  throw new ConflictError('Email exists', { email });
}
```

### Bad Request
```typescript
if (!validInput) {
  throw new BadRequestError('Invalid input', { field: 'value' });
}
```

## Custom Errors

```typescript
import { BaseError } from '@erp-suite/core';

export class CustomError extends BaseError {
  readonly statusCode = 400;
  readonly error = 'Custom Error';

  constructor(details?: Record<string, unknown>) {
    super('Custom error message', details);
  }
}
```

## Error Response

```json
{
  "statusCode": 404,
  "error": "Not Found",
  "message": "User not found",
  "details": { "userId": "999" },
  "timestamp": "2025-12-12T10:30:00.000Z",
  "path": "/api/users/999",
  "requestId": "uuid-here"
}
```

## Request ID Middleware

### NestJS
```typescript
@Injectable()
export class RequestIdMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    const id = req.headers['x-request-id'] || randomUUID();
    req.headers['x-request-id'] = id;
    res.setHeader('X-Request-ID', id);
    next();
  }
}
```

### Express
```typescript
function requestIdMiddleware(req, res, next) {
  const id = req.headers['x-request-id'] || randomUUID();
  req.requestId = id;
  res.setHeader('X-Request-ID', id);
  next();
}

app.use(requestIdMiddleware);
```

## Testing

```typescript
it('should return 404', async () => {
  const res = await request(app)
    .get('/users/999')
    .expect(404);

  expect(res.body).toMatchObject({
    statusCode: 404,
    error: 'Not Found',
    message: 'User not found'
  });
});
```

## DON'Ts

❌ Don't use generic Error
```typescript
throw new Error('Not found'); // Bad
```

❌ Don't try/catch in controllers (NestJS)
```typescript
try {
  return await service.findById(id);
} catch (e) {
  throw new HttpException('Error', 500);
}
```

❌ Don't handle errors manually (Express)
```typescript
try {
  const user = await findUser(id);
  res.json(user);
} catch (e) {
  res.status(500).json({ error: 'Error' });
}
```

## DOs

✅ Use specific error classes
```typescript
throw new NotFoundError('User not found', { userId: id });
```

✅ Let filter/middleware handle (NestJS)
```typescript
async getUser(id: string) {
  return this.service.findById(id);
}
```

✅ Use asyncHandler (Express)
```typescript
app.get('/users/:id', asyncHandler(async (req, res) => {
  const user = await findUser(req.params.id);
  res.json(user);
}));
```

✅ Add contextual details
```typescript
throw new ValidationError('Validation failed', {
  errors: validationErrors
});
```
