Error handling in HAPI - error-handling

Catch all and any errors in a hapi request lifecycle.
I have a signup handler,
public signup(request: Hapi.Request, reply: Hapi.Base_Reply) {
this.database.user.create(request.payload).then((user: any) => {
return reply({
"success": true
});
}).catch((err) => {
reply(Boom.conflict('User with the given details already exists'));
});
}
Now, I am catching the error, but I can't be always sure that I will get this error message only. What if there is an error in the database?
How to catch such database errors or any other unknown errors for all the requests. ???

Maybe you have to return the err.message in your reply like
reply(Boom.conflig(err.message))
or if you want to manage or manipulate the error you have to verify the type of error like
if (err instanceof DatabaseError) {
// manage database error
}

I figured out a way to handle such errors in Hapi.
What I was looking for was a PreResponse handler. Now, the PreResponse handler can log all the errors and I can throw a 500 error response.
What I am saying is by simply writing
reply(err)
I can send a 500 error and can catch this error using preResponse handler. Something like this,
server.ext('onPreResponse', (request: Hapi.Request, reply: Hapi.ReplyWithContinue) => {
const response = request.response;
if (!response.isBoom) { // if not error then continue :)
return reply.continue();
}
console.log(response);
return reply(response);
});

Related

Handling 422 error with axios inside service.js

I have a service.js which has some axios requests. When I post something using this service from view, I can't handle errors, because all errors falls into success chain instead of error.
This line is from service.js
async createIsp(payload) {
return await apiService.post('/isp', payload)
}
And this one is from view:
function saveIsp() {
clicked.value = true
ApiService.createIsp({isp_name: newIsp.value}).then((data) => {
clicked.value = false
//all response falls here... even its error.
//router.push({name: 'isp'})
}).catch(e => console.log(e))
https://stackoverflow.com/a/70542347/3054818
This is the solution. I am using interceptors, and I should throw error.

Lambda doesn't reattempt processing the SQS message even after an error is returned from the handler

I am trying to invoke the lambda function using standard SQS. I have handled errors using a try-catch block and whenever an error is caught, it will be returned. Otherwise, a response message will be returned with 200 OK.
I want to reprocess the messages which returned errors. But lambda won't reprocess those messages.
Even the Retention time period(5 min) > Visibility time out(1 min)
Why does this happen?
const { spawnSync, execSync } = require('child_process');
const fs = require('fs');
const { S3Client, GetObjectCommand, PutObjectCommand } = require("#aws-sdk/client-s3");
const { DynamoDBClient, UpdateItemCommand } = require("#aws-sdk/client-dynamodb");
const { marshall } = require('#aws-sdk/util-dynamodb');
exports.lambdaHandler = async (event) => {
try {
const body = JSON.parse(event["Records"][0]['body']);
try {
// Code base 1
// All the above imported dependencies will be used here
const response = {
statusCode: 200,
body: JSON.stringify({ message: "Function Executed" })
};
console.log('Response: ',response);
return response;
}
catch (err) {
console.log("[ERROR]: ", err);
console.log('body is: ', body);
console.log("err returning");
return err;
}
}
catch (error) {
console.log("[ERROR]: ", error);
console.log("error returning");
return error;
}
};
// Below functions are used in code base 1
// No try catch block or error hadling in below code bases
async function downloadFile() {
//code base 2
};
async function uploadFile() {
// code base 3
};
async function updateUsdz() {
// code base 4
}
You are, as you say, literally returning the error. However, for lambda in this scenario, you're simply returning an object. It does not matter whether or not the object is an error object or any other object. According to the system, your lambda will have been successfully executed, the SQS service will receive a success response from AWS Lambda and the message will be dropped from the queue as it is handled.
If you want to use the retry functionality that SQS provides, you must ensure that you're lambda fails. In this case, this means actually throwing the error again after you've executed the code you want to execute on failure (e.g., logging the error). If you throw the error, the handler function will fail (instead of simply returning an error object) and the message will not be deleted from the SQS queue but will be retried.
For example:
exports.lambdaHandler = async (event) => {
try {
// Do something
} catch (error) {
console.log("[ERROR]: ", error);
throw error;
}
};
As a side note, if you're using a solution like this, ensure you are attaching a dead-letter queue to your SQS queue in order to catch messages that can never be handled by the lambda. If you do not have such a queue to catch those messages, these will keep being retried which effectively creates an infinite loop which could cost quite a lot of money.

Nuxt.js - 'error not defined' when trying to throw 404 in failed await call within asyncData method

Starting to play with Nuxt.js this evening and mock blog data but having an issue with non existing data.
Heres my asyncData method when viewing a single blog post:
async asyncData({ params }) {
try {
const post = await axios.get(
`https://jsonplaceholder.typicode.com/posts/${params.id}`
)
return {
post: post.data
}
} catch (err) {
error({ statusCode: 404, message: 'Post not found' })
}
}
When visiting a valid ID and a 200 error is returned everything works as expected, but when the endpoint returns a 404 it tells me that 'error is undefined'
I could only find information on doing this error handling using a promise catch method as seen here: https://nuxtjs.org/guide/async-data/#handling-errors
How can I use the error method within the try catch error?
Thanks.
You have to inject the error object in your asyncData method to use it inside:
async asyncData({ error, params }) {
// your code
}

Angular GlobalErrorHandler and HttpErrorResponse - Resolver throwing badly formatted HttpErrorResponse

I've created global error handler in my Angular 6 application:
main error handler method:
handleError(error: Error | HttpErrorResponse) {
const router = this.injector.get(Router);
const notificationService = this.injector.get(NotificationsService);
this._logger(error);
if (!navigator.onLine) {
notificationService.displayNotification('error', 'timespan', {heading: 'Internet connection lost!', body: ''});
} else if (error instanceof HttpErrorResponse) {
notificationService.displayNotification('error', 'click', this._httpErrorMessage(error));
} else {
// CLIENT error
router.navigate(['/error-page']);
}
}
Problem:
Many of HTTP service calls are being performed in resolvers:
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<ClientDetailsModel> {
if (route.params.cif) {
const reqBody = new GetClientDetailsRequestModel({cif: route.params.cif, idWewPrac: this.userContext.getUserSKP()});
return this.clientsService.getClientDetails(reqBody)
.pipe(
map((clientDetails: { customerDetails: ClientDetailsModel }) => {
if (clientDetails.customerDetails) {
return clientDetails.customerDetails;
}
return null;
})
);
}
If Http error occurs in such a call, error received by my global error handler is formed as HttpErrorResponse wrapped inside Error (message of Error is HttpErrorResponse):
Uncaught (in promise): HttpErrorResponse: {"headers":{"normalizedNames":{},"lazyUpdate":null},"status":400,"statusText":"OK","url":"https://...
If Http errors occurs outside of resolvers global error handler works perfectly fine.
To reach my goal (throwing HttpErrorResponse from resolver) I need to specify the way to handle error in error callback inside subscription, but I cannot do it because resolver is the one who manages subscription.
Is there a way to specify how resolver should handle errors?
I would like to avoid manual parsing of these wrapped errors.
I was searching for a solution, but could only create a work-a-round.
This will check for the HttpErrorResponse text and tries to parse the JSON which results into the real error object.
Not great at all, but better then nothing.
handleError(error: any): void {
console.error('Errorhandler catched error: ' + error.message, error);
// We need to have this little hack in oder to access the real error object
// The Angular resolver / promise wraps the error into the message, serialized as json.
// So we extract this error again.
// But first lets check if we actually dealing with an HttpErrorResponse ...
if (error.message.search('HttpErrorResponse: ')) {
// The error includes an HTTPErrorResponse, so we try to parse it's values ...
const regex = new RegExp('^.*HttpErrorResponse:\\s(\\{.*\\})$');
const matches = regex.exec(error.message);
if (matches !== null) {
// matches the regex, convert...
const httpErrorResponse = JSON.parse(matches[1]); // This is now the real error object with all the fields
this.handleHttpErrorResponse(httpErrorResponse);
} else {
// It contains HttpErrorResponse, but no JSON part...
this.toastr.error('There was an unknown communication error',
'Communication error',
{timeOut: 10000});
}
} else {
this.toastr.error('Unknown error occured',
'Well that should not happen. Check the log for more information...',
{timeOut: 10000});
}
}

HapiJS reply being called twice

I'm getting this error message with the snippet below
Unhandled rejection Error: reply interface called twice
Note that I'm using return for all the reply() interface
Locations
.findOne({
_id: request.params.id,
activationCode: payload.activationCode
}).then((location) => {
if (!location) {
return reply(Boom.notFound('Location not found'))
}
locationObject = location
if (payload.password !== payload.confirmPassword) {
return reply(Boom.badRequest('Password and Confirm Password must match'))
}
if (!payload.terms) {
return reply(Boom.badRequest('Must agree to Terms & Conditions'))
}
return newPaymentMethod.save()
}).then((paymentMethod) => {
.....
return user.save() // user is defined at .....
}).then(() => {
return reply({ token: helpers.createJwt(userObject) })
}).catch((err) => {
return reply(Boom.wrap(err))
})
Any help would be appreciated.
Looks like you get caught into this due to the incorrect use of promises. I guess you’re executing your snippet within a route handler where you’ve access to reply.
As you’re returning your responses within the promise chain, you both return the value to the next .then (promise) and also calling the reply from the outer scope.
I suggest you use a promise reject for errors so that you only need a single reply(Boom.method()) within the promise’s .catch().
Since you chain promises in the end
.then(() => {
return reply({ token: helpers.createJwt(userObject) })
}).catch((err) => {
return reply(Boom.wrap(err))
})
you might call reply twice if any of if conditions is true.
Easy solution would be to throw error in if condition is true - since there is already a Boom.wrap in catch block.