buydadip
buydadip

Reputation: 9417

How to throw an error inside the pre handler in Hapi.js

I started using v17 of Hapi.js and I am running into issues when using the pre-handler.

I want to save a user into a database, but first I use the pre-handler to check if a user already exists. If the user exists, I want to throw an error. The structure of my route is as so...

module.exports = {
    method: "POST",
    path: "/users",
    config: {
        auth: false,
        pre: [{ method: verify_unique_user}],
        handler: create_user.create
    }
}

The content of verify_unique_user is...

async function verify_unique_user(req, h) {

    await User.findOne({
        $or: [{email: req.payload.email}, {username: req.payload.username}]
    },
    (err, user) => {

        if (user) {

            // Check if username exists.
            if (user.username === req.payload.username) {
                throw Boom.badRequest("Username taken!");
            }

            // Check if email exists.
            if (user.email === req.payload.email) {
                throw Boom.badRequest("Email taken!");
            }
        }

    });

    return req;
}

Let's assume the user already exists in the database. Then an error will be thrown from either of the if statements. When this happens, I get the following error...

events.js:167

 throw er; // Unhandled 'error' event

 ^

Error: Username taken! at User.findOne (/Users/ericbolboa/Desktop/Warble/server/src/users/util/user_function.js:16:16)

This crashed my server. This is not what I want. If I throw an error in my handler function, the response looks like this...

{
    "statusCode": 400,
    "error": "Bad Request",
    "message": "error"
}

But whenever I throw an error in the pre-handler, my server crashes. How can I throw errors properly?

Upvotes: 1

Views: 2674

Answers (2)

Thomas E
Thomas E

Reputation: 3838

Take a look at the toolkit(h) and options.response.failAction of route.

A route can set response.failAction in options. There, you can format error messages, and send response, however you please. That includes errors thrown from pre handlers.

Edit: Every pre-handler can have it's own 'failAction' handler. You must do a response(...).takeover() if you want to halt the chain.

Upvotes: 1

Katherine R
Katherine R

Reputation: 1158

Not sure if this is the source of the issue but you can simplify the async/await instead of using the callback

async function verify_unique_user(req, h) {

    const user = await User.findOne({
        $or: [{email: req.payload.email}, {username: req.payload.username}]
    });

    // Check if username exists.
    if (user.username === req.payload.username) {
        throw Boom.badRequest("Username taken!");
    }

    // Check if email exists.
    if (user.email === req.payload.email) {
        throw Boom.badRequest("Email taken!");
    }

    return req;
}

Upvotes: 3

Related Questions