Theo
Theo

Reputation: 2042

Send custom error message, with serverless-http (express)

I need to send custom error message in JSON format, from my express app, served in a lambda function using serverless-http

Please correct me if i got it wrong, but as i understand it, we need to use LAMBA_PROXY APIG integration to be able to send custom error messages defined directly from a lambda function.

This is what i have tried so far:

res.status(400).json({ message: 'email already taken' });

serverless.yml

functions:
  auth:
    handler: src/express/auth/index.handler
    name: ${self:service}-auth-${env:STAGE}
    # warmup: true
    integration: lambda-proxy
    memorySize: 128
    timeout: 15
    events:
        - http:
            path: /auth/
            method: ANY
            cors: true
        - http:
            path: /auth/{any+}
            method: ANY
            cors: true

this is what the API is returning(with status code 400)

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Error</title>
    </head>
    <body>
        <pre>Bad Request</pre>
    </body>
</html>

Any leads, on how I can send a custom response, in JSON format?

update: After more tests, I found out that calling next(error) doesn't reach the last error handler


const register = async (req, res, next) {
  try {
    await verifyEmail(req.body.email);
    const user = await Users.register(req.body);
    const token = sign(user.attrs, {});
    res.json({ token, user });
  } catch (e) {
    next(e);
  }
};

const generalError = async (err, req, res, next) => {
  // doesn't reach this part! :(
  console.log('generalError handler', JSON.stringify(err));
  res.status(errorOut.status).json(errorOut);
};

ApiRouter.post('/register', register);
app.use('/auth', ApiRouter);
app.use(generalError);

Upvotes: 1

Views: 1406

Answers (1)

romellem
romellem

Reputation: 6491

(I just answered a very similar question here)

Yes, this is explained in the Express docs under Error Handling.

Express comes with a built-in error handler that takes care of any errors that might be encountered in the app. This default error-handling middleware function is added at the end of the middleware function stack.

If you pass an error to next() and you do not handle it in a custom error handler, it will be handled by the built-in error handler; the error will be written to the client with the stack trace. The stack trace is not included in the production environment.

To override this handler, refer to the section in the Express docs titled Writing error handlers.

It explains:

Define error-handling middleware functions in the same way as other middleware functions, except error-handling functions have four arguments instead of three: (err, req, res, next). For example:

app.use(function (err, req, res, next) {
  console.error(err.stack)
  res.status(500).send('Something broke!')
})

You define error-handling middleware last, after other app.use() and routes calls

So in your case, if you wanted to respond with a 400 and some JSON, you might write something like this:

const serverless = require('serverless-http');
const express = require('express');
const app = express();

// Your middleware and other routes here
app.use(/* register your middleware as normal */);

// Finally, your custom error handler
app.use(function customErrorHandler(err, req, res, next) {
   res.status(400).json({ message: 'email already taken' });
});

module.exports.handler = serverless(app);

Upvotes: 2

Related Questions