tryError Documentation

Integration Guides

Learn how to integrate tryError with popular frameworks, libraries, and tools

Express.js Integration

Integrate tryError with Express.js for consistent error handling across your API routes.

Express.js Error Handling Middlewaretypescript
1import express from 'express';
2import { tryAsync, isTryError } from '@try-error/core';
3
4const app = express();
5
6// Error handling middleware
7const handleTryError = (req: express.Request, res: express.Response, next: express.NextFunction) => {
8  return async (handler: (req: express.Request, res: express.Response) => Promise<any>) => {
9    const result = await tryAsync(() => handler(req, res));
10    
11    if (isTryError(result)) {
12      console.error('Route error:', result);
13      
14      // Map error types to HTTP status codes
15      const statusCode = getStatusCodeFromError(result);
16      
17      res.status(statusCode).json({
18        error: {
19          message: result.message,
20          type: result.type,
21          ...(process.env.NODE_ENV === 'development' && {
22            stack: result.stack,
23            context: result.context
24          })
25        }
26      });
27    }
28  };
29};
30
31function getStatusCodeFromError(error: TryError): number {
32  switch (error.type) {
33    case 'ValidationError': return 400;
34    case 'AuthenticationError': return 401;
35    case 'AuthorizationError': return 403;
36    case 'NotFoundError': return 404;
37    case 'ConflictError': return 409;
38    case 'RateLimitError': return 429;
39    default: return 500;
40  }
41}
42
43// Usage in routes
44app.get('/users/:id', handleTryError(async (req, res) => {
45  const userId = req.params.id;
46  
47  if (!userId) {
48    throw new Error('User ID is required');
49  }
50  
51  const user = await fetchUser(userId);
52  res.json(user);
53}));
54
55app.post('/users', handleTryError(async (req, res) => {
56  const userData = req.body;
57  
58  // Validation
59  const validationResult = validateUserData(userData);
60  if (isTryError(validationResult)) {
61    throw validationResult;
62  }
63  
64  const newUser = await createUser(userData);
65  res.status(201).json(newUser);
66}));

Next.js Integration

Use tryError in Next.js API routes and server components for robust error handling.

API Routes

Next.js API Route with tryErrortypescript
1// pages/api/users/[id].ts
2import { NextApiRequest, NextApiResponse } from 'next';
3import { tryAsync, isTryError } from '@try-error/core';
4
5export default async function handler(req: NextApiRequest, res: NextApiResponse) {
6  if (req.method !== 'GET') {
7    return res.status(405).json({ error: 'Method not allowed' });
8  }
9
10  const result = await tryAsync(async () => {
11    const { id } = req.query;
12    
13    if (typeof id !== 'string') {
14      throw new Error('Invalid user ID');
15    }
16    
17    return await fetchUser(id);
18  });
19
20  if (isTryError(result)) {
21    console.error('API Error:', result);
22    
23    const statusCode = result.message.includes('Invalid') ? 400 : 500;
24    return res.status(statusCode).json({
25      error: result.message,
26      ...(process.env.NODE_ENV === 'development' && {
27        details: result.context
28      })
29    });
30  }
31
32  res.json(result);
33}

App Router (Next.js 13+)

Next.js App Router with tryErrortypescript
1// app/api/users/[id]/route.ts
2import { NextRequest, NextResponse } from 'next/server';
3import { tryAsync, isTryError } from '@try-error/core';
4
5export async function GET(
6  request: NextRequest,
7  { params }: { params: { id: string } }
8) {
9  const result = await tryAsync(async () => {
10    const user = await fetchUser(params.id);
11    return user;
12  });
13
14  if (isTryError(result)) {
15    return NextResponse.json(
16      { error: result.message },
17      { status: 500 }
18    );
19  }
20
21  return NextResponse.json(result);
22}
23
24// Server Component
25export default async function UserPage({ params }: { params: { id: string } }) {
26  const result = await tryAsync(() => fetchUser(params.id));
27  
28  if (isTryError(result)) {
29    return (
30      <div className="error-container">
31        <h1>Error Loading User</h1>
32        <p>{result.message}</p>
33      </div>
34    );
35  }
36  
37  return (
38    <div>
39      <h1>{result.name}</h1>
40      <p>{result.email}</p>
41    </div>
42  );
43}

Prisma Integration

Wrap Prisma operations with tryError for consistent database error handling.

Prisma Service with tryErrortypescript
1import { PrismaClient, Prisma } from '@prisma/client';
2import { tryAsync, isTryError, createTryError, fromThrown } from '@try-error/core';
3
4const prisma = new PrismaClient();
5
6// Helper to map Prisma errors to domain errors
7function mapPrismaError(error: unknown) {
8  if (error instanceof Prisma.PrismaClientKnownRequestError) {
9    switch (error.code) {
10      case 'P2002':
11        return createTryError('ConflictError', 'Resource already exists', {
12          field: error.meta?.target,
13          originalError: error
14        });
15      case 'P2025':
16        return createTryError('NotFoundError', 'Resource not found', {
17          originalError: error
18        });
19      case 'P2003':
20        return createTryError('ValidationError', 'Foreign key constraint failed', {
21          field: error.meta?.field_name,
22          originalError: error
23        });
24    }
25  }
26  
27  // Return the original error wrapped
28  return fromThrown(error);
29}
30
31// Database service with tryError - no try-catch needed!
32export class UserService {
33  static async findById(id: string) {
34    const result = await tryAsync(() => prisma.user.findUnique({
35      where: { id },
36      include: { posts: true }
37    }));
38
39    if (isTryError(result)) {
40      return mapPrismaError(result);
41    }
42    
43    if (!result) {
44      return createTryError('NotFoundError', `User with id ${id} not found`, {
45        userId: id
46      });
47    }
48    
49    return result;
50  }
51
52  static async create(data: Prisma.UserCreateInput) {
53    const result = await tryAsync(() => prisma.user.create({ data }));
54    
55    if (isTryError(result)) {
56      return mapPrismaError(result);
57    }
58    
59    return result;
60  }
61
62  static async update(id: string, data: Prisma.UserUpdateInput) {
63    const result = await tryAsync(() => prisma.user.update({
64      where: { id },
65      data
66    }));
67    
68    if (isTryError(result)) {
69      return mapPrismaError(result);
70    }
71    
72    return result;
73  }
74
75  static async delete(id: string) {
76    const result = await tryAsync(() => prisma.user.delete({ 
77      where: { id } 
78    }));
79    
80    if (isTryError(result)) {
81      return mapPrismaError(result);
82    }
83    
84    return { success: true };
85  }
86}
87
88// Usage
89async function handleUserRequest(userId: string) {
90  const userResult = await UserService.findById(userId);
91  
92  if (isTryError(userResult)) {
93    if (userResult.type === 'NotFoundError') {
94      return { status: 404, error: 'User not found' };
95    }
96    if (userResult.type === 'ConflictError') {
97      return { status: 409, error: 'Conflict' };
98    }
99    return { status: 500, error: 'Database error' };
100  }
101  
102  return { status: 200, data: userResult };
103}

Zod Integration

Combine tryError with Zod for robust input validation and error handling.

Zod Validation with tryErrortypescript
1import { z } from 'zod';
2import { trySync, isTryError, createTryError } from '@try-error/core';
3
4// Schema definitions
5const UserSchema = z.object({
6  name: z.string().min(2, 'Name must be at least 2 characters'),
7  email: z.string().email('Invalid email format'),
8  age: z.number().min(18, 'Must be at least 18 years old').optional(),
9});
10
11const CreateUserSchema = UserSchema.extend({
12  password: z.string().min(8, 'Password must be at least 8 characters'),
13});
14
15// Validation helper
16function validateWithTryError<T>(schema: z.ZodSchema<T>, data: unknown) {
17  return trySync(() => {
18    const result = schema.safeParse(data);
19    
20    if (!result.success) {
21      const errors = result.error.errors.map(err => ({
22        field: err.path.join('.'),
23        message: err.message,
24        code: err.code
25      }));
26      
27      throw createTryError('ValidationError', 'Validation failed', {
28        validationErrors: errors,
29        invalidData: data
30      });
31    }
32    
33    return result.data;
34  });
35}
36
37// Usage in API routes
38export async function createUser(userData: unknown) {
39  // Validate input
40  const validationResult = validateWithTryError(CreateUserSchema, userData);
41  
42  if (isTryError(validationResult)) {
43    return validationResult; // Return validation error
44  }
45  
46  // Proceed with validated data
47  const result = await tryAsync(async () => {
48    const hashedPassword = await hashPassword(validationResult.password);
49    
50    return await UserService.create({
51      name: validationResult.name,
52      email: validationResult.email,
53      age: validationResult.age,
54      password: hashedPassword
55    });
56  });
57  
58  return result;
59}
60
61// Express middleware for validation
62function validateBody<T>(schema: z.ZodSchema<T>) {
63  return (req: express.Request, res: express.Response, next: express.NextFunction) => {
64    const validationResult = validateWithTryError(schema, req.body);
65    
66    if (isTryError(validationResult)) {
67      return res.status(400).json({
68        error: 'Validation failed',
69        details: validationResult.context?.validationErrors
70      });
71    }
72    
73    req.body = validationResult;
74    next();
75  };
76}

Jest Testing Integration

Test your tryError implementations effectively with Jest custom matchers and utilities.

Custom Jest Matchers

Jest Custom Matchers for tryErrortypescript
1// jest-setup.ts
2import { isTryError } from '@try-error/core';
3
4declare global {
5  namespace jest {
6    interface Matchers<R> {
7      toBeTryError(): R;
8      toBeTrySuccess(): R;
9      toHaveErrorType(type: string): R;
10      toHaveErrorMessage(message: string | RegExp): R;
11    }
12  }
13}
14
15expect.extend({
16  toBeTryError(received) {
17    const pass = isTryError(received);
18    
19    if (pass) {
20      return {
21        message: () => `expected ${received} not to be a TryError`,
22        pass: true,
23      };
24    } else {
25      return {
26        message: () => `expected ${received} to be a TryError`,
27        pass: false,
28      };
29    }
30  },
31
32  toBeTrySuccess(received) {
33    const pass = !isTryError(received);
34    
35    if (pass) {
36      return {
37        message: () => `expected ${received} not to be a successful result`,
38        pass: true,
39      };
40    } else {
41      return {
42        message: () => `expected ${received} to be a successful result`,
43        pass: false,
44      };
45    }
46  },
47
48  toHaveErrorType(received, expectedType) {
49    if (!isTryError(received)) {
50      return {
51        message: () => `expected ${received} to be a TryError`,
52        pass: false,
53      };
54    }
55    
56    const pass = received.type === expectedType;
57    
58    if (pass) {
59      return {
60        message: () => `expected error type not to be ${expectedType}`,
61        pass: true,
62      };
63    } else {
64      return {
65        message: () => `expected error type ${received.type} to be ${expectedType}`,
66        pass: false,
67      };
68    }
69  },
70
71  toHaveErrorMessage(received, expectedMessage) {
72    if (!isTryError(received)) {
73      return {
74        message: () => `expected ${received} to be a TryError`,
75        pass: false,
76      };
77    }
78    
79    const pass = typeof expectedMessage === 'string' 
80      ? received.message === expectedMessage
81      : expectedMessage.test(received.message);
82    
83    if (pass) {
84      return {
85        message: () => `expected error message not to match ${expectedMessage}`,
86        pass: true,
87      };
88    } else {
89      return {
90        message: () => `expected error message "${received.message}" to match ${expectedMessage}`,
91        pass: false,
92      };
93    }
94  },
95});

Test Examples

Jest Tests with tryErrortypescript
1// user.test.ts
2import { UserService } from './user-service';
3
4describe('UserService', () => {
5  describe('findById', () => {
6    it('should return user when found', async () => {
7      const result = await UserService.findById('existing-id');
8      
9      expect(result).toBeTrySuccess();
10      expect(result).toEqual(expect.objectContaining({
11        id: 'existing-id',
12        name: expect.any(String),
13        email: expect.any(String)
14      }));
15    });
16
17    it('should return NotFoundError when user does not exist', async () => {
18      const result = await UserService.findById('non-existent-id');
19      
20      expect(result).toBeTryError();
21      expect(result).toHaveErrorType('NotFoundError');
22      expect(result).toHaveErrorMessage(/User with id .* not found/);
23    });
24  });
25
26  describe('create', () => {
27    it('should create user successfully', async () => {
28      const userData = {
29        name: 'John Doe',
30        email: 'john@example.com'
31      };
32      
33      const result = await UserService.create(userData);
34      
35      expect(result).toBeTrySuccess();
36      expect(result).toEqual(expect.objectContaining(userData));
37    });
38
39    it('should return ConflictError for duplicate email', async () => {
40      const userData = {
41        name: 'Jane Doe',
42        email: 'existing@example.com'
43      };
44      
45      const result = await UserService.create(userData);
46      
47      expect(result).toBeTryError();
48      expect(result).toHaveErrorType('ConflictError');
49      expect(result).toHaveErrorMessage('User already exists');
50    });
51  });
52});
53
54// Testing validation
55describe('User validation', () => {
56  it('should validate user data successfully', () => {
57    const validData = {
58      name: 'John Doe',
59      email: 'john@example.com',
60      age: 25
61    };
62    
63    const result = validateWithTryError(UserSchema, validData);
64    
65    expect(result).toBeTrySuccess();
66    expect(result).toEqual(validData);
67  });
68
69  it('should return validation error for invalid data', () => {
70    const invalidData = {
71      name: 'J', // Too short
72      email: 'invalid-email',
73      age: 15 // Too young
74    };
75    
76    const result = validateWithTryError(UserSchema, invalidData);
77    
78    expect(result).toBeTryError();
79    expect(result).toHaveErrorType('ValidationError');
80    expect(result.context?.validationErrors).toHaveLength(3);
81  });
82});

TypeScript Configuration

Optimize your TypeScript configuration for the best tryError experience.

Recommended tsconfig.jsonjson
1{
2  "compilerOptions": {
3    "strict": true,
4    "exactOptionalPropertyTypes": true,
5    "noUncheckedIndexedAccess": true,
6    "noImplicitReturns": true,
7    "noFallthroughCasesInSwitch": true,
8    "noImplicitOverride": true,
9    "allowUnusedLabels": false,
10    "allowUnreachableCode": false,
11    
12    // For better error handling
13    "useUnknownInCatchVariables": true,
14    
15    // Module resolution
16    "moduleResolution": "node",
17    "esModuleInterop": true,
18    "allowSyntheticDefaultImports": true,
19    
20    // Path mapping for cleaner imports
21    "baseUrl": ".",
22    "paths": {
23      "@/*": ["src/*"],
24      "@/types/*": ["src/types/*"],
25      "@/utils/*": ["src/utils/*"]
26    }
27  },
28  "include": [
29    "src/**/*",
30    "tests/**/*",
31    "jest-setup.ts"
32  ]
33}

Key Configuration Benefits

  • strict: true - Enables all strict type checking
  • exactOptionalPropertyTypes: true - Better optional property handling
  • noUncheckedIndexedAccess: true - Safer array/object access
  • useUnknownInCatchVariables: true - Safer error handling in catch blocks

Error Monitoring Services

Integrate tryError with popular error monitoring and analytics services to track, analyze, and debug errors in production.

Sentry Integration

Sentry provides real-time error tracking and performance monitoring. Integrate it with tryError for comprehensive error insights.

Complete Sentry Integrationtypescript
1// 1. Install Sentry
2// pnpm add @sentry/nextjs
3
4// 2. Initialize Sentry (sentry.client.config.ts)
5import * as Sentry from '@sentry/nextjs';
6
7Sentry.init({
8  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
9  environment: process.env.NODE_ENV,
10  integrations: [
11    Sentry.replayIntegration(),
12    Sentry.feedbackIntegration({ colorScheme: 'auto' }),
13  ],
14  tracesSampleRate: process.env.NODE_ENV === 'production' ? 0.1 : 1.0,
15  replaysSessionSampleRate: 0.1,
16  replaysOnErrorSampleRate: 1.0,
17});
18
19// 3. Configure tryError with Sentry
20import { configure } from '@try-error/core';
21
22configure({
23  onError: (error) => {
24    // Capture in Sentry with rich context
25    Sentry.captureException(error, {
26      tags: {
27        errorType: error.type,
28        source: error.source?.file,
29        tryError: true,
30      },
31      contexts: {
32        tryError: {
33          type: error.type,
34          message: error.message,
35          timestamp: error.timestamp,
36          source: error.source,
37        },
38      },
39      extra: {
40        context: error.context,
41        metadata: error.metadata,
42      },
43    });
44
45    // Set user context if available
46    if (error.context?.userId) {
47      Sentry.setUser({
48        id: error.context.userId,
49        email: error.context.userEmail,
50      });
51    }
52
53    return error;
54  },
55});
56
57// 4. Usage in your application
58export async function processOrder(orderId: string) {
59  // Add breadcrumb for better debugging
60  Sentry.addBreadcrumb({
61    category: 'order',
62    message: 'Processing order',
63    level: 'info',
64    data: { orderId },
65  });
66
67  const result = await tryAsync(async () => {
68    const order = await api.processOrder(orderId);
69    
70    if (!order.success) {
71      throw createTryError('OrderProcessingError', order.error.message, {
72        orderId,
73        errorCode: order.error.code,
74        // Rich context for Sentry
75        orderDetails: order.details,
76        customerInfo: order.customer,
77      });
78    }
79    
80    return order;
81  });
82
83  if (isTryError(result)) {
84    // Add additional Sentry context for specific errors
85    Sentry.withScope((scope) => {
86      scope.setTag('order.failed', true);
87      scope.setContext('order', {
88        id: orderId,
89        error: result.message,
90      });
91      scope.setLevel('error');
92    });
93  }
94
95  return result;
96}

Sentry Benefits with tryError

  • • Automatic error grouping by TryError type
  • • Rich context from tryError's structured errors
  • • Source location tracking for better debugging
  • • Performance monitoring with error correlation
  • • Session replay on errors for debugging

Vercel Analytics Integration

Track error metrics and user impact with Vercel Analytics custom events.

Vercel Analytics Error Trackingtypescript
1// 1. Install Vercel Analytics
2// pnpm add @vercel/analytics
3
4// 2. Setup Analytics in your layout
5import { Analytics } from '@vercel/analytics/react';
6import { track } from '@vercel/analytics';
7import { configure } from '@try-error/core';
8
9// 3. Configure tryError to track errors
10configure({
11  onError: (error) => {
12    // Track error occurrence
13    track('error_occurred', {
14      errorType: error.type,
15      errorMessage: error.message,
16      source: error.source?.file || 'unknown',
17      path: typeof window !== 'undefined' ? window.location.pathname : 'server',
18      // Don't send sensitive data
19      severity: getSeverityLevel(error),
20      category: categorizeError(error),
21    });
22
23    // Track specific error types with custom events
24    switch (error.type) {
25      case 'ValidationError':
26        track('validation_error', {
27          fields: error.context?.validationErrors?.length || 0,
28          form: error.context?.formName,
29        });
30        break;
31      
32      case 'APIError':
33        track('api_error', {
34          endpoint: error.context?.endpoint,
35          statusCode: error.context?.statusCode,
36          duration: error.context?.duration,
37        });
38        break;
39      
40      case 'PaymentError':
41        track('payment_error', {
42          amount: error.context?.amount,
43          currency: error.context?.currency,
44          provider: error.context?.provider,
45        });
46        break;
47    }
48
49    return error;
50  },
51});
52
53// 4. Track error recovery and user actions
54export function CheckoutForm() {
55  const handleSubmit = async (formData) => {
56    const startTime = Date.now();
57    const result = await tryAsync(() => processCheckout(formData));
58
59    if (isTryError(result)) {
60      // Track failed checkout
61      track('checkout_failed', {
62        errorType: result.type,
63        duration: Date.now() - startTime,
64        step: result.context?.step || 'unknown',
65      });
66
67      // Track user recovery actions
68      if (result.type === 'PaymentError') {
69        track('payment_retry_shown', {
70          errorCode: result.context?.errorCode,
71        });
72      }
73    } else {
74      // Track successful checkout
75      track('checkout_success', {
76        duration: Date.now() - startTime,
77        amount: formData.amount,
78      });
79    }
80
81    return result;
82  };
83}
84
85// 5. Error Analytics Dashboard
86export function RootLayout({ children }) {
87  return (
88    <html lang="en">
89      <body>
90        {children}
91        <Analytics 
92          mode={process.env.NODE_ENV}
93          beforeSend={(event) => {
94            // Redact sensitive URLs
95            if (event.url.includes('/admin') || 
96                event.url.includes('/api/internal')) {
97              return null;
98            }
99            return event;
100          }}
101        />
102      </body>
103    </html>
104  );
105}

Analytics Insights with tryError

  • • Error rate tracking by type and severity
  • • User impact analysis with custom events
  • • Recovery rate metrics for better UX
  • • A/B testing error rates across features
  • • Real-time error dashboards

Other Monitoring Services

tryError can integrate with any error monitoring service through its flexible configuration API.

Generic Error Service Integrationtypescript
1import { configure } from '@try-error/core';
2import { Bugsnag, LogRocket, Rollbar, DataDog } from './monitoring-services';
3
4configure({
5  onError: (error) => {
6    // Send to multiple services
7    const errorPayload = {
8      type: error.type,
9      message: error.message,
10      timestamp: error.timestamp,
11      context: error.context,
12      stack: error.stack,
13      source: error.source,
14    };
15
16    // Bugsnag
17    if (typeof Bugsnag !== 'undefined') {
18      Bugsnag.notify(error, (event) => {
19        event.addMetadata('tryError', errorPayload);
20      });
21    }
22
23    // LogRocket
24    if (typeof LogRocket !== 'undefined') {
25      LogRocket.captureException(error, {
26        tags: { errorType: error.type },
27        extra: errorPayload,
28      });
29    }
30
31    // Rollbar
32    if (typeof Rollbar !== 'undefined') {
33      Rollbar.error(error.message, error, {
34        tryError: errorPayload,
35      });
36    }
37
38    // DataDog
39    if (typeof DataDog !== 'undefined') {
40      DataDog.logger.error(error.message, {
41        error: errorPayload,
42        service: 'frontend',
43        env: process.env.NODE_ENV,
44      });
45    }
46
47    // Custom logging endpoint
48    if (process.env.NODE_ENV === 'production') {
49      fetch('/api/errors', {
50        method: 'POST',
51        headers: { 'Content-Type': 'application/json' },
52        body: JSON.stringify({
53          error: errorPayload,
54          userAgent: navigator.userAgent,
55          timestamp: new Date().toISOString(),
56        }),
57      }).catch(() => {
58        // Silently fail if logging fails
59      });
60    }
61
62    return error;
63  },
64});

Error Monitoring Best Practices

  • 1. Don't log sensitive data: Always sanitize error context before sending to external services
  • 2. Use sampling in production: For high-traffic apps, sample errors to control costs. See our comprehensive sampling guide
  • 3. Set up alerts: Configure alerts for critical error types and error rate spikes
  • 4. Track error trends: Monitor error rates over time to catch regressions early
  • 5. Correlate with deployments: Link error spikes to specific deployments for faster debugging

Related Pages

Migration Guides

Step-by-step migration from other error handling approaches

View Migration Guides →

Best Practices

Learn recommended patterns and performance tips

View Best Practices →

React Integration

Specific guidance for React applications

View React Guide →