Reputation:
I want to give a proper error handling, in my endpoint, in this case i try to do some syntax error in raw json body request in postman.
i dont want the response like this
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>SyntaxError: Unexpected token a in JSON at position 125<br> at JSON.parse (<anonymous>)<br> at parse (/Users/admin/Documents/NEW-SOURCE/security/boost-svc-consumer/node_modules/body-parser/lib/types/json.js:89:19)<br> at /Users/admin/Documents/NEW-SOURCE/security/boost-svc-consumer/node_modules/body-parser/lib/read.js:121:18<br> at invokeCallback (/Users/admin/Documents/NEW-SOURCE/security/boost-svc-consumer/node_modules/raw-body/index.js:224:16)<br> at done (/Users/admin/Documents/NEW-SOURCE/security/boost-svc-consumer/node_modules/raw-body/index.js:213:7)<br> at IncomingMessage.onEnd (/Users/admin/Documents/NEW-SOURCE/security/boost-svc-consumer/node_modules/raw-body/index.js:273:7)<br> at emitNone (events.js:106:13)<br> at IncomingMessage.emit (events.js:208:7)<br> at IncomingMessage.wrapped [as emit] (/Users/admin/Documents/NEW-SOURCE/security/boost-svc-consumer/node_modules/newrelic/lib/transaction/tracer/index.js:193:22)<br> at endReadableNT (_stream_readable.js:1064:12)<br> at _combinedTickCallback (internal/process/next_tick.js:138:11)<br> at process._tickCallback (internal/process/next_tick.js:180:9)</pre>
</body>
</html>
I want give some custom message. Like "Unknown error or syntax error in json request", I gave try catch in my controller fucntion but looks like try catch doesnt catch it" it throw error befor it come in to the try catch block.
do you know hot to do it ?
Thanks in advance
Upvotes: 1
Views: 1144
Reputation: 3425
Yes, you can do it easily if you are working with express.
Below is the code of my api server that you can find the sources HERE.
I'm using typescript but the same can be achieved with javascript at 0 cost.
ErrorMiddleware
This middleware can catch any error thrown. As you can see there is a specific SyntaxError that can catch malformed JSON and reply to the client.
import { Response, Request, NextFunction } from 'express';
import { UnauthorizedError } from 'express-jwt';
import logger from '@app/logger';
import { EnvUtil } from '@app/util';
import { ResponseHelper, HttpStatusCode } from '@app/helper';
import { EmptyFileError } from '@app/common/error';
export default class ErrorMiddleware {
public static handle(err: Error, _req: Request, res: Response, _next: NextFunction): void {
if (err instanceof UnauthorizedError) {
logger.warn(`Authentication with JWT failed due to ${err.message}`);
ResponseHelper.send(res, HttpStatusCode.UNAUTHORIZED);
} else if (err instanceof SyntaxError) {
logger.warn(`Malformed JSON due to ${err.message}`);
ResponseHelper.send(res, HttpStatusCode.BAD_REQUEST, [err.message]);
} else {
logger.error(`Internal Server error due to ${err.message}`);
ResponseHelper.send(
res,
HttpStatusCode.INTERNAL_SERVER_ERROR,
EnvUtil.isDevelopment() ? err.stack : undefined
);
}
}
}
Express app
When you create the Express app remember to register (with use) the ErrorMiddleware. I register the error middleware Here.
import express from 'express';
import bodyParser from 'body-parser';
import { ErrorMiddleware } from '@app/middleware';
const app = express();
// JSON body parser
app.use(bodyParser.json())
// Before error middleware configure all your express app
app.use(ErrorMiddleware.handle);
ResponseHelper
This class handle the response given the res express parameter, http status code you want to return and some data (optional). You can find the implementation Here.
You can find the implementation of httpStatusCode Here
As you can see the interface Response is the mapping for all API responses with:
import { Response as ExpressResponse } from 'express';
import HttpStatusCode, { Status } from './httpStatusCode';
export interface Response {
status: Status;
is_success: boolean;
status_code: number;
status_code_name: string;
data: object;
}
export default class ResponseHelper {
public static send(
res: ExpressResponse,
httpStatusCode: HttpStatusCode,
data: any = undefined
): void {
res
.status(httpStatusCode.code)
.json(<Response>{
status: httpStatusCode.status(),
is_success: httpStatusCode.isSuccess(),
status_code: httpStatusCode.code,
status_code_name: httpStatusCode.name,
data,
})
.end();
}
}
You can test the application sending malformed JSON at the following URL: https://racer-2020.herokuapp.com/api/v1/car
The error response will be the following:
{
"status": "fail",
"is_success": false,
"status_code": 400,
"status_code_name": "Bad Request",
"data": [
"Unexpected end of JSON input"
]
}
In the source code you can find other middleware that handle for example a not found route path.
Hope it helps :)
Upvotes: 1