skip to Main Content

I’m new to express about a few weeks old and i came in with the assumption that error handling will be just as easy as it is with springboot. I was wrong. So I have this express app set up in this way:

  1. request comes in and is intercepted by middleware like so
// auth endpoint
app.use(`/api/v1/auth`, authRouter)
  1. request is sent to router
// login router
router.route("/login").post(authController.handleLogin);
  1. The router
const handleLogin = async (req: Request, res: Response<AuthResponse>) => {
  try {
    const body: UserAuthenticationBody = req.body;
    const isAuthenticated = await authService.authenticate(body); // Assuming authenticate returns a boolean indicating authentication status
    console.log({ accessTokenSecret })
    if (isAuthenticated) {
      const user: UserDocument = await userService.getUserProfile(body.username);
      console.log(user);
      const accessToken = jwt.sign({
        _id: user._id,
        firstname: user.firstname,
        lastname: user.lastname,
        username: body.username,
      }, accessTokenSecret, { expiresIn: '2h' });

      console.log("Here-1")
      return res.status(HttpStatusCode.BAD_REQUEST).json({
        message: "Authentication successful",
        status: HttpStatusCode.OK,
        data: {
          accessToken: accessToken
        }
      });
    } else {
      console.log("Here-2")
      return res.status(401).json({
        message: "Authentication failed",
        status: HttpStatusCode.UNAUTHORIZED
      });
    }
  } catch (err: any) {
    console.log("Here-3")

    return res.status(HttpStatusCode.INTERNAL_SERVER_ERROR).json({
      message: err.message,
      status: HttpStatusCode.INTERNAL_SERVER_ERROR
    });
  }
}
  1. The auth service that is being called
const authenticate = async (credentials: UserAuthenticationBody): Promise<boolean> => {
  try {
  const user: UserDocument | null = await User.findOne({
    $or: [
      { username: credentials.username },
      { email: credentials.username }
    ]
  });

  if (!user) {
    // User not found
    throw new Error("user does not exist");
  }

  // Compare the provided password with the hashed password stored in the database
  const passwordMatch = await bcrypt.compare(credentials.password, user.password);
  return passwordMatch;
  }
  catch (error: any) {
    console.log("error in auth");
    throw error;
  }
}

**
The problem is that when a user is not found an error is thrown and the catch clause in handle login is indeed triggered but the response status is OK despite me having specified to say it should it should be a 500 INTERNAL_SERVER_ERROR. Whats even more confusing that the message returned from the response json object is "user does not exist" **

I did check the value of the enum INTERNAL_SERVER ERROR and it is 500.
I tried using a global handler but i think i’m might have misconfigured it so i am not sure if i was doing it right.

What am i doing wrong?

this is what the rest of my server index looks like

import dotenv from "dotenv";
dotenv.config();

import express, { Request, Response, NextFunction } from "express";
import compression from "compression";
import cors from "cors";
import http from "http";
import { Server as SocketIoServer, Socket } from "socket.io";
import mongoose from "mongoose";
import { connectDB } from "./config/DbConfigurations";
import { ChatMessage } from "./api/v1/models";

// Connect to DB
connectDB();

const app = express();
const server = http.createServer(app);
const io = new SocketIoServer(server, {
  cors: {
    origin: "*",
    methods: "*"
  }
});
const port = process.env.PORT || 5000;

// middleware 
app.use(express.json());
// app.use(compression());

app.use(cors());

// Make sure request has a bearer token unless its 
import { authController } from "./api/v1/controllers";
// app.use(authController.authenticateToken)

import {
  authRouter,
  usersRouter,
  groupsRouter,
  journalsRouter
} from "./api/v1/routes/index";

// Error handling middleware
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
  console.error(err.stack);
  res.status(500).json({
    message: 'Internal Server Error',
    status: 500
  });
});

// auth endpoint
app.use(`/api/v1/auth`, authRouter)

// users endpoint
app.use(`/api/v1/users`, usersRouter);

// journals endpoint
app.use("/api/v1/journals", journalsRouter)

// groups  endpoint
app.use(`/api/v1/groups`, groupsRouter)

// Socket.IO connection handler
io.on('connection', (socket: Socket) => {
  console.log('A user connected');

  // Join a chat room based on the pair of users
  socket.on('joinChat', (data) => {
    console.log("Chat created")
    const { sender, receiver } = data;
    const room = [sender, receiver].sort().join('-');
    socket.join(room);
  });

  // Handle incoming messages
  socket.on('chatMessage', async (data) => {
    const { sender, receiver, content } = data;
    // Broadcast the message to the appropriate chat room
    const chatRoom = [sender, receiver].sort().join('-');
    const message = new ChatMessage({ chatRoom, sender, receiver, content, timestamp: new Date() });
    await message.save();


    io.to(chatRoom).emit('chatMessage', message);

  });

  // Handle disconnections
  socket.on('disconnect', () => {
    console.log('A user disconnected');
  });
});

// Only if we connect to a DB should we listen to api requests
mongoose.connection.once('open', () => {
  console.log("Connected to MongoDB");
  server.listen(port, () => console.log("server listening on port: ", port));

})

2

Answers


  1. Chosen as BEST ANSWER

    Did a thorough debugging and the express app is returning the correct status. The problem was the the routes in nextjs frontend. I completely forgot about them.

    this was it before

    export async function POST(req: NextRequest, res: NextResponse) {
      try {
        const { username, password } = await req.json();
        const url = `${API_URL}/api/v1/auth/login`;
        console.log(url)
        const response = await fetch(`${url}`, {
          cache: "no-cache",
          method: "POST",
          headers: {
            "Content-Type": "application/json"
          },
          body: JSON.stringify({
            username,
            password
          })
        })
    
        if (response.ok) {
          // some code if res is ok
          return new Response(JSON.stringify(message), {
            status: 200,
            headers: { "Set-Cookie": serialized },
          });
        }
        else {
          // problem starts here
          const data = await response.json()
          console.log(data);
          throw new Error(data.message);
        }
      }
      catch (e: any) {
        console.log(e);
        // this defaults to a 200
        return NextResponse.json({ 
          message: e?.message,
          data: null,
          status: 500
        });
      }
    }
    

    NextResponse.json defaulted to 200 because i didn't specify the status code. This is what it looks like now. Was a simple solution, just an oversight.

    This is after

    export async function POST(req: NextRequest, res: NextResponse) {
      try {
        // ... rest of the code
    
        if (response.ok) {
          // some code if res is ok
          return new Response(JSON.stringify(message), {
            status: 200,
            headers: { "Set-Cookie": serialized },
          });
        }
        else {
          return response; // decided to return server response to the client instead
        }
      }
      catch (e: any) {
        console.log(e);
        // Fixed this and used the Response object instead
        return new Response(JSON.stringify({ 
          message: e?.message,
          data: null,
          status: 500
        }), {status: 500});
      }
    }
    

  2. I don’t have enough reputation to comment your post, so instead I’m posting an answer, this did happen to me one time, HttpStatusCode.BAD_REQUEST was not working in my project, I don’t know why, so instead I sent 400 as an int:

    res.status(400)
    

    Try it and let me know if this did work for you, otherwise i’ll just delete my answer.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search