try-error Documentation
Integration Guides
Learn how to integrate try-error with popular frameworks, libraries, and tools
Express.js Integration
Integrate try-error 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';
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 try-error in Next.js API routes and server components for robust error handling.
API Routes
Next.js API Route with try-errortypescript
1// pages/api/users/[id].ts
2import { NextApiRequest, NextApiResponse } from 'next';
3import { tryAsync, isTryError } from 'try-error';
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 try-errortypescript
1// app/api/users/[id]/route.ts
2import { NextRequest, NextResponse } from 'next/server';
3import { tryAsync, isTryError } from 'try-error';
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 try-error for consistent database error handling.
Prisma Service with try-errortypescript
1import { PrismaClient, Prisma } from '@prisma/client';
2import { tryAsync, isTryError, createTryError } from 'try-error';
3
4const prisma = new PrismaClient();
5
6// Database service with try-error
7export class UserService {
8 static async findById(id: string) {
9 return tryAsync(async () => {
10 const user = await prisma.user.findUnique({
11 where: { id },
12 include: { posts: true }
13 });
14
15 if (!user) {
16 throw createTryError('NotFoundError', `User with id ${id} not found`, {
17 userId: id
18 });
19 }
20
21 return user;
22 });
23 }
24
25 static async create(data: Prisma.UserCreateInput) {
26 return tryAsync(async () => {
27 try {
28 return await prisma.user.create({ data });
29 } catch (error) {
30 if (error instanceof Prisma.PrismaClientKnownRequestError) {
31 if (error.code === 'P2002') {
32 throw createTryError('ConflictError', 'User already exists', {
33 field: error.meta?.target,
34 originalError: error
35 });
36 }
37 }
38 throw error;
39 }
40 });
41 }
42
43 static async update(id: string, data: Prisma.UserUpdateInput) {
44 return tryAsync(async () => {
45 try {
46 return await prisma.user.update({
47 where: { id },
48 data
49 });
50 } catch (error) {
51 if (error instanceof Prisma.PrismaClientKnownRequestError) {
52 if (error.code === 'P2025') {
53 throw createTryError('NotFoundError', `User with id ${id} not found`, {
54 userId: id
55 });
56 }
57 }
58 throw error;
59 }
60 });
61 }
62
63 static async delete(id: string) {
64 return tryAsync(async () => {
65 try {
66 await prisma.user.delete({ where: { id } });
67 } catch (error) {
68 if (error instanceof Prisma.PrismaClientKnownRequestError) {
69 if (error.code === 'P2025') {
70 throw createTryError('NotFoundError', `User with id ${id} not found`, {
71 userId: id
72 });
73 }
74 }
75 throw error;
76 }
77 });
78 }
79}
80
81// Usage
82async function handleUserRequest(userId: string) {
83 const userResult = await UserService.findById(userId);
84
85 if (isTryError(userResult)) {
86 if (userResult.type === 'NotFoundError') {
87 return { status: 404, error: 'User not found' };
88 }
89 return { status: 500, error: 'Database error' };
90 }
91
92 return { status: 200, data: userResult };
93}
Zod Integration
Combine try-error with Zod for robust input validation and error handling.
Zod Validation with try-errortypescript
1import { z } from 'zod';
2import { trySync, isTryError, createTryError } from 'try-error';
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 try-error implementations effectively with Jest custom matchers and utilities.
Custom Jest Matchers
Jest Custom Matchers for try-errortypescript
1// jest-setup.ts
2import { isTryError } from 'try-error';
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 try-errortypescript
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 try-error 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