NodeJS PUT request returns error 400 (Bad Request)

10,674

Solution 1

In your fetch request you are sending only avatar as a body and on your updateUser function you have the following if statement:

if (!req.body._id){
    return res.status(400).json({status: 400, message: "Id must be present"})
}

so obviously you have not _id on your body request but an avatar instead, in fact you're sending your id as a param

'http://localhost:3003/user/edit/:id'

So you could change this line as a workaround

if (!req.params.id){

Hope it helps.

Solution 2

The below snippet shows that you are trying to get the ID parameter from the body of the request.

if (!req.body._id){
    return res.status(400).json({status: 400, message: "Id must be present"})
}

Whereas, the route /user/edit/:id , shows that the ID parameter is actually passed through the URL, and to access it, all you need is to get your ID from the URL using req.params.id. req.params contains all parameters that are passed through the route or URL path.

The above snippet should be corrected to;

if (!req.params.id){
    return res.status(400).json({status: 400, message: "Id must be present"})
}

Check https://expressjs.com/en/guide/routing.html#route-parameters for proper guide on how to deal with route parameter.

Share:
10,674

Related videos on Youtube

someonewithakeyboardz1
Author by

someonewithakeyboardz1

Updated on June 04, 2022

Comments

  • someonewithakeyboardz1
    someonewithakeyboardz1 almost 2 years

    I am trying to do a PUT request with NodeJS, Express and MongoDB. The issue that I am currently having is that I keep receiving an error **400** and I am not sure exactly why.

    What I am exactly trying to do is upload edit a field in my USER collection, after a certain user has been registered. This is supposed to happen on a specific /user/edit/:id route.

    My application is structured with a standard MVC pattern.

    Here is how my Mongo Schema is structured:

    let UserSchema = new mongoose.Schema({
      username: String,
      password: String,
      email: String,
      avatar: String,
      firstName: String,
      lastName: String,
      laps:[{ type: Schema.Types.ObjectId, ref: 'Stats' }]
    });
    

    This is my service:

    exports.updateUser = async function(user) {
      let id = user.id;
      let oldUser;
      try {
        //Find the old User Object by the Id
        oldUser = await User.findById(id);
      } catch(e) {
        throw Error("Error occured while Finding the User");
      }
      // If no old User Object exists return false
      if (!oldUser) {
        return false;
      }
      //Edit the User Object
      oldUser.firstName = user.firstName || oldUser.firstName;
      oldUser.lastName = user.lastName || oldUser.lastName;
      oldUser.avatar = user.avatar || oldUser.avatar;
      try {
        let savedUser = await oldUser.save();
        return savedUser;
      } catch(e) {
        throw Error("And Error occured while updating the User");
      }
    };
    

    The Controller that I am using:

    exports.updateUser = async function(req, res, next) {
      if (!req.body._id){
        return res.status(400).json({status: 400, message: "Id must be present"})
      }
      let id = req.body._id;
      let user = {
        id,
        firstName: req.body.firstName || null,
        lastName: req.body.lastName || null,
        avatar: req.body.avatar || null
      };
      try {
        let updatedUser = await UserService.updateUser(user);
        return res.status(200).json({status: 200, data: updatedUser, message: "Successfully Updated User"})
      } catch(e) {
        return res.status(400).json({status: 400, message: e.message})
      }
    };
    

    Route path in router file:

    router.post('/edit/:id', UserController.updateUser);
    

    Route path for users inside server file:

    app.use('/user', require('./api/routes/user.route'));
    

    I know that most 4** errors come from the front end of the application, so I will also post my form and the constructor behind it. I am using ReactJS as a framework.

    Front end Form:

    class UserProfile extends Component {
      constructor(props) {
        super(props);
        this.state = {
          avatar: '',
          resultsSubmitted: false
        };
        this.formChange = this.formChange.bind(this);
        this.resultsSubmit = this.resultsSubmit.bind(this);
      }
      formChange(e) {
        console.log("form changed" + e.target);
        const { name, value } = e.target;
        this.setState({ [name]: value });
      }
      resultsSubmit(e) {
        e.preventDefault();
        const accessToken = JSON.parse(localStorage.getItem('auth_user')).data.access_token;
        const { avatar } = this.state;
        const { dispatch } = this.props;
        if (avatar) {
          console.log("submitting results: " + avatar);
          dispatch(userActions.addAvatar(avatar, accessToken));
        }
      }
      render(){
          const { avatar, resultsSubmitted} = this.state;
        return (
          <div className="container-fluid no-gutters page-login">
            <div className="row">
              <div className="login-wrapper">
                <h2> Edit User Profile </h2>
    
                <form onSubmit={this.resultsSubmit}>
                  <div className="form-group">
                    Paste Avatar URL: <input type="text" value={avatar} name="avatar" id="" onChange={this.formChange} />
                  </div>
                  <input type="submit" className="btn btn-primary btn-lg btn-block" value="submit"/>
                </form>
    
              </div>
            </div>
          </div>
        )
      }
    }
    function mapStateToProps(state) {
      const { layout } = state;
      return {
        layout
      };
    }
    export default connect(mapStateToProps)(UserProfile);
    

    My dispatch:

    function addAvatar(avatar, token) {
      return dispatch => {
        dispatch(request());
        userService.addAvatar(avatar, token)
          .then(
            user => {
              dispatch(success(user));
              history.push(`${process.env.PUBLIC_URL}/`);
            },
            error => {
              dispatch(failure(error));
              dispatch(alertActions.error(error));
            }
          );
      };
      function request() { return { type: userConstants.AVATAR_REQUEST } }
      function success(user) { return { type: userConstants.AVATAR_SUCCESS, user } }
      function failure(error) { return { type: userConstants.AVATAR_FAILURE, error } }
    }
    

    HTTP Post service:

    function addAvatar(avatar){
      const requestOptions = {
        method: 'POST',
        headers: authHeader(),
        body:  avatar
      };
      return fetch('http://localhost:3003/user/edit/:id', requestOptions)
        .then(response => {
          if (!response.ok) {
            console.log("+",response,"+");
            return Promise.reject(response.statusText);
          }else{
            console.log(response, "the user service response was gooooooooooood");
          }
          return response.json();
        })
        .then(data => console.log(data,"WHT DO WE HAVE HERE?"));
    }
    

    Apologies for the huge code wall but I wanted to include all the bits.

    I am getting an error 400 (Bad Request) on the route POST http://localhost:3003/user/edit/:id

    • Tholle
      Tholle about 5 years
      What error do you get in the Network tab of the Developer Tools? It might be a CORS issue.
    • SalmaFG
      SalmaFG about 5 years
      I'm thinking it might be because the id field does not have a key in the user JSON object you're creating. Could you try changing it to id: id and see if it helps?
  • someonewithakeyboardz1
    someonewithakeyboardz1 about 5 years
    yes but I am receiving null as an input from somewhere