1

I'm attempting to build a MEAN app and trying to test POSTing with POSTMAN. When I do, I keep getting the dreaded "TypeError: Cannot read property 'name' of undefined". If I type in a simple string, the POST goes through fine. But when I use "req.body.name" I get the error. I've looked in every place and I'm not seeing my mistake. I even followed the suggestions on this thread with no luck. Any help or suggestions would be greatly appreciated.

Here's the code I am currently working with in my server.js file:

    const express = require('express');
var bodyParser = require('body-parser');
var Bear = require('./models/bear')
var path = require('path');
var mongoose = require('mongoose');
var router = express.Router();

var app = express();


var staticAssets = __dirname + '/public';

    app.use(express.static(staticAssets));


    app.use('/api', router)
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({extended: true}));


// Routes for my API
//===================================

// middleware to use for all requests
router.use(function(req,res,next){
    // logging happens here
    console.log('Something will happen.');
    next(); // Head to the next router...don't stop here
});

// Test router to make sure everything is working (accessed at GET http://localhost:3000/api)
router.get('/', function(req, res){
    res.json({message: 'hooray! welcome to our api!'})
})

//More routes will happen here with routes that end in "/bears"
router.route('/bears')
    //Create a bear (accessed at POST http://localhost:3000/api/bears)
    .post(function(req,res){
        var bear = new Bear(); // Create a new instance of the bear model
        console.log(req);
        bear.name = req.body.name; // set the bears name (comes from the request)

        //res.send(200, req.body);
        bear.save(function(err){
            if (err)
                res.send(err);
            res.json({message: 'Bear Created!!'});
        });
    });
//======================================

//var Products = require('./products.model.js');
var Product = require('./models/product.model');

var db = 'mongodb://localhost/27017';

mongoose.connect(db);







    var server = app.listen(3000);
console.log("App is listening on port 3000");

Thanks.

Also, the url I'm trying to use inside of POSTMAN is http://localhost:3000/api/bears

peteb
  • 18,552
  • 9
  • 50
  • 62
Joel Carter
  • 151
  • 12
  • 2
    You should include your client request in your question. Another thing is you should move your `app.use(bodyParser.json())` and `app.use(bodyParser.urlencoded({extended: true}))` before ALL of your routes and router middleware. If it doesn't come before them then it will not be used when those routes are handled. So if you're requesting your `/api` router middleware then `bodyParser` wouldn't be used. – peteb Nov 08 '16 at 20:26

1 Answers1

2

Express processes requests Top-Down, meaning if you require a piece of functionality to be applied to all routes via middleware, than that middleware needs to be added to your app before any routes that require it. This is usually the case for middleware such as body-parser.

When using Router Middleware, you don't typically construct the router in the same file as the actual Express app that will use it as middleware. Instead, place it in a separate file and/or directory for organization purposes, this is considered a best practice.

Express Apps can be structured like so

/lib
  /models
    bear.js
    product.js
/node_modules
/public
  /css    
/routes
  api.js
package.json
server.js

The routes directory is where you would place any applicable Router Middleware files such as your api router. server.js is your main Express App and public is where your static assets are stored. lib is directory that contains any business logic files and models.

The actual Express app and Router files should look something like this

server.js

'use strict';

const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');

const apiRouter = require('./routes/api');

const app = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

app.use(express.static(path.join(__dirname, public)));

app.use(/api, apiRouter);

app.listen(port, () => {
    console.log(`Listening on port ${port});
});

module.exports = app; 

routes/api.js

'use strict';

const router = require('express').Router();
const Bear = require('./lib/models/bear');

router.use((req, res, next) => {
    // logging happens here
    console.log('Something will happen.');
    next(); // Head to the next router...don't stop here
});

router.get('/', (req, res) => {
    return res.json({ message: 'hooray! welcome to our api!'})
});

router.route('/bears')
    //Create a bear (accessed at POST http://localhost:3000/api/bears)
    .post((req, res) => {
        var bear = new Bear(); // Create a new instance of the bear model

        console.log(req);
        bear.name = req.body.name; // set the bears name (comes from the request)

        //res.send(200, req.body);
        bear.save((err) => {
            if (err)
                return res.send(err);

            return res.json({message: 'Bear Created!!'});
        });
    });

module.exports = router;

To note, you could break up your API even further to increase the amount of decoupling. An example of this would be to move the /api/bear route to its own router middleware and into its own route file. Then simply add it to your routes/api.js router as a middleware like you would in server.js. If your app is going to have a decent sized API, then this would be the best approach because it would allow the most flexibility when it comes to applying middleware to only certain routes and would make maintaining the source much easier.

peteb
  • 18,552
  • 9
  • 50
  • 62