Error handling api
Skill JimmyBlanquet/project-forge/production-skills/core/error-handling-api
SaaS factory: Next.js starters + spec-kit extensions + Ralph++ autonomous loop. Production-ready in 48h.
npx -y skills add JimmyBlanquet/project-forge --skill error-handling-apiAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Production-ready API error handling for Next.js with standardized error codes, request tracking, user-friendly messages, and automatic error wrapping. Type-safe responses with logging separation.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
10.3 KB, as published. Nobody here has run it
Error Handling API
Centralized error handling system for Next.js API routes with consistent responses, request tracking, and separation between user-facing messages and technical logs.
When to Use
Use this skill when building Next.js APIs that need:
- Consistent error response format across all endpoints
- User-friendly error messages (never expose internal details)
- Request ID tracking for debugging
- Automatic error catching and logging
- Type-safe error codes and responses
- Separation between client errors (4xx) and server errors (5xx)
Don't use this skill if:
- You're building a simple static site without APIs
- You need GraphQL error handling (this is REST-focused)
- You're using Next.js Pages Router (this uses App Router Route Handlers)
Stack
- Next.js 14+ (App Router Route Handlers)
- TypeScript (strict mode)
- Optional: Logging library integration (Pino, Winston, etc.)
Quick Start
1. Install Skill
npm install -D @project-forge/error-handling-api
2. Create Error Codes Dictionary
// lib/api/errors.ts
import { API_ERROR } from '@project-forge/error-handling-api'
// Use predefined errors or extend with your own
export const AppErrors = {
...API_ERROR,
CUSTOM_ERROR: {
code: 'CUSTOM_ERROR',
message: 'Your custom error message',
status: 400,
},
} as const
3. Use in API Routes
// app/api/users/route.ts
import { apiError, apiSuccess } from '@project-forge/error-handling-api'
import { NextRequest } from 'next/server'
export async function GET(request: NextRequest) {
const userId = request.nextUrl.searchParams.get('id')
if (!userId) {
return apiError('MISSING_PARAMS')
}
const user = await db.users.findUnique({ where: { id: userId } })
if (!user) {
return apiError('NOT_FOUND')
}
return apiSuccess(user)
}
4. Wrap Routes with Error Handler
import { withErrorHandler } from '@project-forge/error-handling-api'
export const POST = withErrorHandler(async (request) => {
// Any unhandled errors are caught and returned as 500
const data = await processData()
return apiSuccess(data)
})
Key Features
Standard Error Codes
Pre-defined error codes for common scenarios:
Authentication (401)
UNAUTHORIZED- Authentication requiredSESSION_EXPIRED- Session expired, please reconnect
Authorization (403)
FORBIDDEN- Access deniedRESOURCE_FORBIDDEN- No access to this resource
Not Found (404)
NOT_FOUND- Resource not foundPROFILE_NOT_FOUND,EMAIL_NOT_FOUND, etc.
Validation (400)
VALIDATION_ERROR- Invalid dataINVALID_PARAMS- Invalid parametersMISSING_PARAMS- Required parameters missing
Rate Limiting (429)
RATE_LIMITED- Too many requests
Server Errors (500)
INTERNAL_ERROR- Internal server errorDATABASE_ERROR- Database operation failedSERVICE_UNAVAILABLE- Service temporarily unavailable
Request ID Tracking
Every error response includes a unique request ID for debugging:
{
"error": {
"code": "DATABASE_ERROR",
"message": "Une erreur est survenue, veuillez réessayer"
},
"requestId": "req_abc123_xyz789"
}
Error Response Format
Consistent response format across all errors:
interface ApiErrorResponse {
error: {
code: string
message: string
}
requestId?: string
}
Success Response Format
Consistent success format:
interface ApiSuccessResponse<T> {
data: T
}
User-Friendly Messages
Errors never expose internal details to clients:
// ❌ Bad - Exposes database details
return NextResponse.json({
error: "SQLSTATE[23505]: duplicate key value"
}, { status: 500 })
// ✅ Good - User-friendly message
return apiError('DATABASE_ERROR')
// Returns: "Une erreur est survenue, veuillez réessayer"
Server-Side Logging
Technical details are logged server-side only:
return apiError('DATABASE_ERROR', dbError, {
route: '/api/users',
userId: user.id,
})
// Logs full error details, returns sanitized message to client
Auto-Catching Wrapper
The withErrorHandler wrapper catches all unhandled errors:
export const GET = withErrorHandler(async (request) => {
// If this throws, it's automatically caught and returned as INTERNAL_ERROR
const data = await riskyOperation()
return apiSuccess(data)
})
Custom Error Messages
Override default messages when needed:
return apiError('VALIDATION_ERROR', null, {
customMessage: 'Email must be a valid email address',
})
Core API
apiError(errorType, details?, context?)
Create a standardized error response.
Parameters:
errorType- Error code from error dictionarydetails?- Technical details (logged server-side only)context?- Optional context:{ route?, userId?, customMessage? }
Returns: NextResponse<ApiErrorResponse>
Example:
// Simple error
return apiError('NOT_FOUND')
// With logging
return apiError('DATABASE_ERROR', dbError, {
route: '/api/posts',
userId: user.id
})
// With custom message
return apiError('VALIDATION_ERROR', null, {
customMessage: 'Password must be at least 8 characters'
})
apiSuccess(data, status?)
Create a standardized success response.
Parameters:
data- Response data (any type)status?- HTTP status code (default: 200)
Returns: NextResponse<{ data: T }>
Example:
return apiSuccess({ id: 1, name: 'John' })
return apiSuccess(null, 204) // No content
withErrorHandler(handler)
Wrap route handler with automatic error catching.
Parameters:
handler- Async route handler function
Returns: Wrapped handler with try/catch
Example:
export const POST = withErrorHandler(async (request) => {
const data = await processData()
return apiSuccess(data)
})
Advanced Patterns
Custom Error Classes
For domain-specific errors with metadata:
export class RateLimitError extends Error {
constructor(
public limit: number,
public resetsAt: Date,
public retryable: boolean = false
) {
super(`Rate limit exceeded: ${limit}`)
this.name = 'RateLimitError'
}
}
// Usage
try {
await sendEmail()
} catch (error) {
if (error instanceof RateLimitError) {
return apiError('RATE_LIMITED', error, {
customMessage: `Limit reached. Resets at ${error.resetsAt.toLocaleTimeString()}`,
})
}
throw error
}
See references/CUSTOM_ERROR_CLASSES.md for full pattern.
Retry Logic
Determine if errors are retryable:
export function isRetryable(errorCode: string): boolean {
return ['NETWORK_ERROR', 'SERVICE_UNAVAILABLE', 'INTERNAL_ERROR'].includes(errorCode)
}
Multi-Language Support
Override messages for different locales:
const ERROR_MESSAGES_FR = {
NOT_FOUND: 'Ressource non trouvée',
UNAUTHORIZED: 'Authentification requise',
}
const ERROR_MESSAGES_EN = {
NOT_FOUND: 'Resource not found',
UNAUTHORIZED: 'Authentication required',
}
return apiError('NOT_FOUND', null, {
customMessage: ERROR_MESSAGES_FR.NOT_FOUND,
})
Testing
The skill includes comprehensive test coverage (>70%):
npm test
npm test -- --coverage
Test examples:
- Error response format validation
- Request ID generation
- Status code correctness
- Logging integration
- Custom message override
- withErrorHandler wrapper behavior
Examples
The skill includes 4 production-ready examples:
-
Basic API Route (
examples/01-basic-route.ts)- Simple GET/POST with error handling
- Validation and not-found scenarios
-
Advanced Error Handling (
examples/02-advanced-errors.ts)- Custom error classes
- Retry logic
- Logging integration
-
Protected Routes (
examples/03-protected-route.ts)- Authentication errors
- Authorization errors
- Resource ownership checks
-
Batch Operations (
examples/04-batch-operations.ts)- Partial success handling
- Error aggregation
- Transaction rollback
Integration with Auth
Works seamlessly with auth-supabase-complete skill:
import { requireAuth } from '@project-forge/auth-supabase-complete/require-auth'
import { apiError, apiSuccess } from '@project-forge/error-handling-api'
export const GET = async (request: NextRequest) => {
const { user, error } = await requireAuth(supabaseConfig, request)
if (error) return error // Already formatted with apiError
const data = await fetchUserData(user.id)
return apiSuccess(data)
}
Troubleshooting
Errors not being caught?
- Ensure you're using
withErrorHandlerwrapper - Check that errors are thrown (not returned)
- Verify async/await usage
Request IDs not showing?
- Request IDs are auto-generated for all errors
- Check the
requestIdfield in error response - Ensure you're using
apiError()function
Custom messages not working?
- Pass
customMessagein context object - Don't modify the error dictionary directly
- Use for user-specific validation messages only
Logging not working?
- The skill logs via
console.errorby default - Integrate with your logger in
logError()utility - See
references/LOGGER_INTEGRATION.md
Best Practices
- Never expose internal details - Use generic messages for 5xx errors
- Use specific error codes - Helps with debugging and analytics
- Log context - Include route, userId, and operation details
- Consistent format - Always use
apiError()andapiSuccess() - Custom messages for validation - Be specific about what's invalid
- Wrap all routes - Use
withErrorHandleras a safety net - Track request IDs - Include in logging dashboards for correlation
Performance
- Zero runtime overhead for success cases
- Request ID generation: ~0.01ms
- Error formatting: ~0.1ms
- Minimal memory footprint (~2KB per error)
License
MIT - See LICENSE file for details
Documentation Version: 1.0.0 Last Updated: 2026-01-17 Skill Compatibility: Claude Code 2.1+, Claude Desktop, Claude.ai Pro/Max