Home
Support Forums

Receiving Error code 500 with the correct body

Hello,

I have a nextjs website with an api. When I run a local server with npm, everything works as expected. But once deployed on netlify, on my api calls, I receive the expected response body with the correct data but with a 500 error code.

One example of my api function is as follow :

handler.delete((req, res) => {
  req.logOut();
  res.status(204).end();
});

I tried running a netlify cli dev to see if I could get more information but I get stuck with a “error while proxying request: socket hang up” and indefinitely loading page on localhost:8888, if that’s relevant

Do you have any ideas or need more information to help solve my problem ? Thank you in advance !

Hi @Adamska,

A little more info would be probably helpful. For example, is the API being run by Netlify Functions? Also, if you could share a more significant part of the code, that can actually show what’s wrong.

Hi @hrishikesh

Thank you for your answer. I am not using Netlify Functions. I am calling with ‘fetch’ my api route which are handled with next-connect npm package.

Here is the file handling the login and logout

import nc from 'next-connect';
import { all } from '@/middlewares/index';
import passport from 'middlewares/passport';
import { extractUser } from '@/lib/api-helpers';

const handler = nc();

handler.use(all);

handler.post(passport.authenticate('local'), (req, res) => {
  res.json({ user: extractUser(req.user) });
});

handler.delete((req, res) => {
  req.logOut();
  res.status(204).end();
});

export default handler;

I use middlewares (the ‘all’ variable above), to keep a cached mongoDB connection, session, and user authentication (with passport).

Here are the middlewares:

all.js

import nc from 'next-connect';
import passport from 'middlewares/passport';
import database from './database';
import session from './session';

const all = nc();

all.use(database).use(session).use(passport.initialize()).use(passport.session());

export default all;

database.js

global.mongo = global.mongo || {};

let indexesCreated = false;
export async function createIndexes(db) {
  await Promise.all([
    db
      .collection('tokens')
      .createIndex({ expireAt: -1 }, { expireAfterSeconds: 0 }),
    db.collection('users').createIndex({ email: 1 }, { unique: true }),
  ]);
  indexesCreated = true;
}

export default async function database(req, res, next) {
  if (!global.mongo.client) {
    global.mongo.client = new MongoClient(process.env.MONGODB_URI, {
      useNewUrlParser: true,
      useUnifiedTopology: true,
    });
    await global.mongo.client.connect();
  }
  req.dbClient = global.mongo.client;
  req.db = global.mongo.client.db(process.env.DB_NAME);
  if (!indexesCreated) await createIndexes(req.db);
  return next();
}

session.js

import session from 'express-session';
import connectMongo from 'connect-mongo';

const MongoStore = connectMongo(session);

export default function sessionMiddleware(req, res, next) {
  const mongoStore = new MongoStore({
    client: req.dbClient,
    stringify: false,
  });
  return session({
    secret: process.env.SESSION_SECRET,
    resave: false,
    saveUninitialized: false,
    store: mongoStore,
  })(req, res, next);
}

passport.js

import passport from 'passport';
import bcrypt from 'bcryptjs';
import { Strategy as LocalStrategy } from 'passport-local';
import { findUserById, findUserByEmail } from '@/db/index';

passport.serializeUser((user, done) => {
  done(null, user._id);
});

// passport#160
passport.deserializeUser((req, id, done) => {
  findUserById(req.db, id).then((user) => done(null, user), (err) => done(err));
});

passport.use(
  new LocalStrategy(
    { usernameField: 'email', passReqToCallback: true },
    async (req, email, password, done) => {
      const user = await findUserByEmail(req.db, email);
      if (user && (await bcrypt.compare(password, user.password))) {
        if (user.emailVerified === true) done(null, user);
        else done(null, false, { message: 'Email not verified. Click on the confirmation link sent to your email' });
      } else done(null, false, { message: 'Email or password is incorrect' });
    },
  ),
);

export default passport;

Does it help ?

Here the code in my navigation component when I call the logout api route from an onClick={handleLogout}:

  const handleLogout = async () => {
    await fetch('/api/auth', {
      method: 'DELETE',
    });
    mutate(null);
    Router.push('/login');
  };

Hi @Adamska,

Thank you so much for the detailed response.

Is this possibly related to: API route as Netlify function 502s · Issue #296 · netlify/netlify-plugin-nextjs · GitHub? In short, the res.end() seems to be a problem.

I don’t think it’s the cause of the problem because I got the same thing with every other λ routes. Most of them don’t use res.status(‘XXX’).end() but res.status(‘XXX’).json(‘yyy’); or res.status(‘XXX’).send(‘yyy’);

I think this can be a good issue for the plugin I mentioned above. If you can provide them a reproducible repo, they can probably check for what exactly is going wrong.