Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitda650b0

Browse files
committed
feat(express): enhance global error handling by adding specific error handlers for MongoDB, Zod, and Mongoose errors; introduce error source tracking in responses
1 parent0f0cc78 commitda650b0

File tree

3 files changed

+135
-20
lines changed

3 files changed

+135
-20
lines changed

‎apps/express/src/middlewares/GlobalErrorHandler.ts

Lines changed: 65 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,82 @@
11
import{logger}from"@/app";
2+
importAppErrorfrom"@/configs/AppError";
23
import{env}from"@/configs/envConfig";
3-
importtype{
4-
ErrorRequestHandler,
5-
NextFunction,
6-
Request,
7-
Response,
8-
}from"express";
4+
import{TErrorSources}from"@/types/error";
5+
import{
6+
handleCastError,
7+
handlerDuplicateError,
8+
handlerValidationError,
9+
handlerZodError,
10+
}from"@/utils/errorHelpers";
11+
import{NextFunction,Request,Response}from"express";
912

10-
importAppErrorfrom"../configs/AppError";
13+
constMONGO_DUPLICATE_KEY_ERROR=11_000;
1114

12-
constGlobalErrorHandler:ErrorRequestHandler=(
13-
err,
14-
_req:Request,
15+
exportconstglobalErrorHandler=(
16+
err:unknown,
17+
req:Request,
1518
res:Response,
16-
_next:NextFunction,
19+
next:NextFunction,
1720
)=>{
18-
letstatusCode:number=err.statusCode??500;
19-
letmessage:string=err.message??`Error:${err.message}`;
20-
// log the error
21-
logger.error(err);
21+
// Log the error in development
2222

23-
if(errinstanceofAppError){
23+
logger.error(`[${req.method}]${req.originalUrl}${req.ip}`,err);
24+
25+
leterrorSources:TErrorSources[]=[];
26+
letstatusCode=500;
27+
letmessage="Something went wrong!";
28+
29+
// Type guards
30+
constisObject=(val:unknown):val isRecord<string,any>=>
31+
typeofval==="object"&&val!==null;
32+
33+
// Duplicate key error (MongoDB)
34+
if(
35+
isObject(err)&&
36+
"code"inerr&&
37+
err.code===MONGO_DUPLICATE_KEY_ERROR
38+
){
39+
constsimplifiedError=handlerDuplicateError(err);
40+
statusCode=simplifiedError.statusCode;
41+
message=simplifiedError.message;
42+
}
43+
// Cast error (invalid ObjectId)
44+
elseif(isObject(err)&&"name"inerr&&err.name==="CastError"){
45+
constsimplifiedError=handleCastError(errasany);
46+
statusCode=simplifiedError.statusCode;
47+
message=simplifiedError.message;
48+
}
49+
// Zod schema validation error
50+
elseif(isObject(err)&&"name"inerr&&err.name==="ZodError"){
51+
constsimplifiedError=handlerZodError(errasany);
52+
statusCode=simplifiedError.statusCode;
53+
message=simplifiedError.message;
54+
errorSources=simplifiedError.errorSources;
55+
}
56+
// Mongoose validation error
57+
elseif(isObject(err)&&"name"inerr&&err.name==="ValidationError"){
58+
constsimplifiedError=handlerValidationError(errasany);
59+
statusCode=simplifiedError.statusCode;
60+
message=simplifiedError.message;
61+
errorSources=simplifiedError.errorSources;
62+
}
63+
// Custom AppError
64+
elseif(errinstanceofAppError){
2465
statusCode=err.statusCode;
2566
message=err.message;
26-
}elseif(errinstanceofError){
67+
}
68+
// General JS error
69+
elseif(errinstanceofError){
2770
message=err.message;
2871
}
2972

3073
res.status(statusCode).json({
3174
success:false,
3275
message,
33-
stack:env.NODE_ENV==="production" ?undefined :err.stack,
76+
errorSources,
77+
...(env.NODE_ENV==="development"&&{
78+
err,
79+
stack:errinstanceofError ?err.stack :undefined,
80+
}),
3481
});
3582
};
36-
37-
exportdefaultGlobalErrorHandler;

‎apps/express/src/types/error/index.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
exporttypeTErrorSources={
2+
path:string|number;
3+
message:string;
4+
};
5+
6+
exporttypeTGenericErrorResponse={
7+
statusCode:number;
8+
message:string;
9+
errorSources:TErrorSources[];
10+
};
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import{TGenericErrorResponse}from"@/types/error";
2+
import{CastError,Error}from"mongoose";
3+
import{ZodError}from"zod";
4+
5+
exportconsthandlerZodError=(err:ZodError):TGenericErrorResponse=>{
6+
consterrorSources=err.issues.map((issue)=>({
7+
path:issue.path.join("."),
8+
message:issue.message,
9+
}));
10+
11+
return{
12+
statusCode:400,
13+
message:"Zod Validation Error",
14+
errorSources,
15+
};
16+
};
17+
18+
exportconsthandlerDuplicateError=(err:any):TGenericErrorResponse=>{
19+
constmatch=err.message.match(/(["'])(\\?.)*?\1/);
20+
constvalue=match ?match[0] :"";
21+
22+
return{
23+
statusCode:409,
24+
message:"Duplicate Key Error",
25+
errorSources:[
26+
{
27+
path:Object.keys(err.keyValue)[0]!,
28+
message:`${value} already exists.`,
29+
},
30+
],
31+
};
32+
};
33+
34+
exportconsthandlerValidationError=(
35+
err:Error.ValidationError,
36+
):TGenericErrorResponse=>{
37+
consterrorSources=Object.values(err.errors).map((val)=>({
38+
path:val.path,
39+
message:val.message,
40+
}));
41+
42+
return{
43+
statusCode:400,
44+
message:"Validation Error",
45+
errorSources,
46+
};
47+
};
48+
49+
exportconsthandleCastError=(err:CastError):TGenericErrorResponse=>{
50+
return{
51+
statusCode:400,
52+
message:"Invalid ObjectId",
53+
errorSources:[
54+
{
55+
path:err.path,
56+
message:`Invalid value for field:${err.path}`,
57+
},
58+
],
59+
};
60+
};

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp