Search code examples
reactjsnext.jsnext-connect

How to handle errors inside getServerSideProps in Next.js using next-connect


I'm using Next.js and next-connect to handle middlewares.

But I'm having problems trying to handle errors when I use several middlewares inside getServerSideProps.

This is the code I have inside getServerSideProps, I just created a handler using several middlewares so then all of them run, the authentication is successful and the user data should be passed to the response, but if any fails, the error should be catched and return a redirect to '/login' page.

import nextConnect from 'next-connect';
import { openDBConnection, retrieveUserInfo } from '@/middlewares/database';
import { verifySessionCookie } from '@/middlewares/firebaseSession';
...
    export const getServerSideProps = async ({ req, res }) => {
        const handler = nextConnect()
            .use(verifySessionCookie)
            .use(openDBConnection)
            .use(retrieveUserInfo);
        try {
            await handler.run(req, res);
            return {
                props: {
                    user: req.user,
                },
            };
        } catch (e) {
            console.log(e);
            return {
                redirect: {
                    destination: '/login',
                    permanent: false,
                }
            };
        }
    }

I didn't define any try/catch block in any of the middlewares, so if an error happens it can be handled in any api page or getServerSideProps block.

Every seemed to be ok when there was only one middeware verifySessionCookie the error is returned when await handler.run(req, res) is called and then handled in the catch block.

But when using the 3 middlewares as it's shown in the piece of code, if the first middleware fails (verifySessionCookie) the error is not handled in the catch block.

I've tried to make the next() call in every middleware, using a finally clause), in this way the error is catched inside getServerSideProps but:

  • verifySessionCookie executes, it fails.
  • openDBConnection executes, it doesn't fail.
  • retrieveUserInfo executes, it fails.

Maybe I'm doing something wrong here, or maybe next-connect is not intended to be used this way. I don't know how can I handle the error in case that one middleware, and all the rest is not executed. Perhaps I should be calling independent async functions with (req, res) parameters inside the getServerSideProps and stop using this next-connect plugin.


Solution

  • the documentation on next-connect says you can add onError on your nextConnect

    function onError(err, req, res, next) {
      logger.log(err);
    
      res.status(500).end(err.toString());
      // OR: you may want to continue
      next();
    }
    
    const handler = nextConnect({ onError });
    

    Or in your middleware, you can pass some value with req to make it more customizable.

    And In the middleware, you can add a try/catch block to pass different values with req

    Something like:

    export const middlewareExample = (req, res, next) => {
      try {
        // ...
        req.condition = {
          status: 'succuss, ...',
          message: '...',
          data: {
            // ...
          }
        }
        next();
      } catch(error) {
        res.status(...).end(...);
        // OR: you may want to continue
        req.condition = {
          status: 'error, ...',
          message: '...',
          data: {
            // ...
          }
        }
        next();
      }
    }
    
    export const getServerSideProps = async ({ req, res }) => {
      const handler = nextConnect()
      .use(verifySessionCookie)
      .use(openDBConnection)
      .use(retrieveUserInfo);
    
      await handler.run(req, res);
    
      if (req.condation.status === 'succuss') {
        return {
          props: {
            user: req.user,
          },
        };
      } else {
        console.log(req.condation.message);
        return {
          redirect: {
            destination: '/login',
            permanent: false,
          }
        };
      }
    })
    

    I hope this helps.