Getting an undefined body in express PUT request

18 views Asked by At

I have a React / Node / Express app where I am trying to update a user.

The Redux action that should be handling the request looks like this:

export const updateUser = (userId: string, data: any) => async (dispatch: any) => {
  try {
    dispatch(setLoadingAction(true));

    const response = await fetch(`http://localhost:5000/api/user/${userId}`, {
      method: 'PUT',
      cache: 'no-cache',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(data)
    });

    const updatedUser = await response.json();
    dispatch(updateUserAction(updatedUser.user));
  } catch (error) {
    dispatch(setErrorAction('error updating user!'));
  }
}

The actual controller endpoint that I am hitting:

exports.updateUser = asyncHandler(async (req: any, res: any, next: any) => {
  const { userId } = req.params;
  console.log(req.body)
  const data = req.body;
  console.log('in controllers/user.ts, userId:', userId);
  console.log('in controllers/user.ts, data:', JSON.stringify(data));

  const user = await updateUser(userId, data);

  res.status(200).json({ user });
});

I have both GET and PUT routes defined for the user:

import express, { Request, Response } from "express";
const router = express.Router();

const userController = require("../controllers/user");

// GET /user/:ipAddress
// router.post("/", userController.createUser);
router.get("/api/user", userController.getUser);
router.put("/api/user/:userId", userController.updateUser);

export { router };

In my server.ts file I am using bodyParser (although I understand that Express should be handling this out of the box, so bodyParser might not be needed.

(async () => {
  const port = env.PORT;
  app.use(express.json());
  app.use(bodyParser.json());
  app.use(bodyParser.urlencoded({ extended: false }));
  app.use('/api/user', userRouter);

  try {
    app.listen(port, () => {
      db.on("error", console.error.bind(console, "connection error:"));
      db.on("connected", function () {
        console.log("Connected to MongoDB");
      });
      console.log(`Server started at http://localhost:${port}`);
    });
  } catch (err) {
    const error = new Error("Request failed");
    console.log(err);
    throw error;
  } finally {
    console.log("Server started");
  }
})();

For some reason, regardless of whether I use cURL, Postman, or try to hit the endpoint via the app itself, the body is null every time, although params seem to be getting passed successfully, and the response I get is always a 200.

Request (using cURL):

`curl -X PUT -H "Content-Type: application/json" -d '{"alignment":"pro"}' http://localhost:5000/api/user/65d73ae14d1a69c64d6787e6

Response:

{"user":{"_id":"65d73ae14d1a69c64d6787e6","ipAddress":"::ffff:127.0.0.1","alignment":"","createdAt":"2024-02-22T12:15:29.745Z","__v":0}}%

I would expect the alignment value on the user to have been set. When I put loggers inside of the updateUser action or the controller endpoint itself, the request data is always undefined.

in controllers/user.ts, userId: 65d73ae14d1a69c64d6787e6
in controllers/user.ts, data: undefined
1

There are 1 answers

0
Misha Krul On

I figured it out.

I needed to pass express.json() as an argument when calling the user controller endpoint.

api/src/routes/user.ts:

router.put("/api/user/:userId", express.json(), userController.updateUser);

api/src/controllers/user.ts:

exports.updateUser = asyncHandler(async (req: any, res: any, next: any) => {
      const { userId } = req.params;
      const data = req.body;
    
      const user = await updateUser(userId, data);
    
      res.status(200).json({ user });
    });

Data is being updated successfully now :)