0

I am sending a post request from my node.js web app to my API. The data that I am sending to my API via post is two strings name and password. At the API end, it is receiving undefined for both strings. I cannot figure out why it is doing this.

Below is my package.json to show relevant packages being used:

{
  "name": "api",
  "version": "1.0.0",
  "description": "",
  "main": "api.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "nodemon -r dotenv/config api.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "dotenv": "^6.0.0",
    "express": "^4.16.3",
    "mongoose": "^5.2.14"
  },
  "devDependencies": {
    "nodemon": "^1.18.4"
  }
}

This is the HTML where the data is being entere by the user:

<!DOCTYPE html>
<html>
    <head>
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" integrity="sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB" crossorigin="anonymous">
        <meta charset="utf-8" />
        <meta name="description" content="A frontend dashboard for the
        TrackMe application" />
        <meta name="author" content="name" />
        <meta name="viewport" content="width=device-width, initialscale=1.0">
        <link rel="stylesheet" href="style.css" />
        <title>TrackMe</title>
    </head>

    <body>
        <div id="navbar"></div>
        <div class="container">
                <h1>Registration</h1>

            <div class="form-group">
                    <label for="user">Username</label>
                    <input type="text" placeholder="Enter Username" class="form-control" id="username" />
                    <div id='messageError' ></div>
            </div>

            <div id='userError'></div>

            <div class="form-group">
                <label for="password">Password</label>
                <input type="text" placeholder="Enter Password" class="form-control" id="password" />
            </div>

            <div class="form-group">
                    <label for="confirm-password"> Confirm Password</label>
                    <input type="text" placeholder="Enter Password" class="form-control" id="confirm-password" />
            </div>

            <div id='passwordError'></div>

            <button class="btn btn-primary" id='register-account' href="/login.html">Register</button>
            <br>
            <br>

            <p>Already have an account? Sign in <a href="/login">here</a>.</p>
        </div>
        <div id="footer"></div> 

        <script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
        <script src="app.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
        <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js" integrity="sha384-smHYKdLADwkXOn1EmN1qk/HfnUcbVRZyYmZ4qpPea6sjB/pTJ0euyQp0Mk8ck+5T" crossorigin="anonymous"></script>
    </body>
</html>

Here is the code for my app.js which is sending the data:

$('#register-account').on('click', function() { 
    const name = $('#username').val();
    const password = $('#password').val();
    const passwordConfirm = $('#confirm-password').val();
    const body = {
        name,
        password
    }
    //Checking password credentials match
    const confirmedPassword = password == passwordConfirm
    if (!confirmedPassword){
        $('#passwordError').append('<p class="alert alert-danger" style="font-style: italic"> ERROR: Password does not match </p>')
    }
    else 
        $.post(`${API_URL}/register`, body)
            .then((response) =>{
                console.log(response);
                if(response.success){
                location.href = "/login"
                // localStorage.setItem('name', name);
                // localStorage.setItem('isAdmin', response.isAdmin);
                }
            })
        .catch(error => {
            console.log(`Error: ${error}`);
        }
)});

the name and password variables are being retrieved via a click handler.

Here is the code from the api end:

app.post('/api/register', (req, res) => {
  const {name, password, isAdmin} = req.body;
  console.log('req.body data from register post endpoint:')
  console.log(req.body);
  User.findOne({ 'name': name }, function (err, user) {
    if(err!=null){
      console.log('Err section api/register');
      return res.json({
        success: false,
        message: err
      });
    }
    else{
      if(user!=null){
        console.log('user !=null api/register');
        // console.log(name);
        // console.log(password);
        return res.json({
          success: false,
          message: "user already exists"
        });
      }
      else{
        console.log(req.body);
        console.log("create new user");
        const newUser = new User({
          name,
          password,
          isAdmin
        });

        newUser.save(err => {
          return err
          ? res.send(err)
          : res.json({
            success: true,
            message: 'Created new user'
          });
        });
      }
    }
  });
});
Xander
  • 27
  • 6
  • 1
    The answer below has you covered, I think, but as an aside, do you really want a user registering themselves to say they are an admin? – Paul Sep 11 '18 at 18:05
  • Im still trying to get my head around that answer below. In reference to the admin part its just a label at this stage. You're right i should probably change the label however it doesn't have any effect on user abilities on the website etc. @Paul – Xander Sep 11 '18 at 18:11
  • Can you post your express config, ie what middleware you’re mounting and so on? – Paul Sep 11 '18 at 18:44
  • I added my package.json, is that what you mean? @Paul – Xander Sep 11 '18 at 19:02
  • 1
    @Xander: No, Paul is talking about how you have setup/initialized your `app`, just as in the question/answer I linked to in my answer attempt. – Hero Wanders Sep 11 '18 at 20:36

2 Answers2

1

I guess you are using the Express framework to setup your server. Maybe you haven't configured it to deserialize the body as JSON? Here is a question and a good answer on how to achieve that: How do I consume the JSON POST data in an Express application

What does the console.log(req.body) print?

Hero Wanders
  • 2,460
  • 1
  • 4
  • 9
  • Ill have a read of that now. console.log(req.body) prints {}. – Xander Sep 11 '18 at 18:04
  • If you insert log statements for name and password into your web app, do they print the expected values? Maybe you actually don't have fields with those IDs (perhaps they only have name attributes assigned). – Hero Wanders Sep 11 '18 at 18:12
  • No, even the console.log of (name) and (password) both return undefined. – Xander Sep 11 '18 at 18:20
  • Then please show us the relevant fragment of your HTML page (or the script which might generate it). – Hero Wanders Sep 11 '18 at 18:51
  • I added the relevant HTML to the post. @Hero – Xander Sep 11 '18 at 19:04
  • @Xander: The data extraction in the browser should work this way, as you can see in this JSFiddle: https://jsfiddle.net/q6o97sn8/ Even with popper and bootstrap added, I still get a working example. Are you sure that username and password are undefined on the client? – Hero Wanders Sep 11 '18 at 20:59
0

So after doing some research, I found that I hadn't included the correct body.parser in my api.js file.

//SOURCE OF THE ERROR WITH THE POST REQUEST
app.use(bodyParser.urlencoded({
  extended: true
}));

I added this chunk of code near the top and the problem is now resolved. Req.body is receiving all the information and the app is now functioning.

Xander
  • 27
  • 6