By default, JavaScript doesn’t have a way to pass information between different files. mod-ule.exportsis Node’s way of fixing this problem.
You can think of module.exportsas a giant object for our application. When our application starts, thismodule.exportsobject looks like this:
1 module.exports = {};
As we start pulling things into our app withrequire(), everything is added to this object.
So now as we add that newconfig.jsfile withrequire(./config.js);, we have access to those variables since we passed them throughmodule.exports.
This is how we will be passing information to and from all of our files and we’ll see this in practice again when we create our routes files.
It is also important to note that many tutorials on the web will switch betweenmodule.exportsand exports. They mean the same thing and can be used interchangeably.
Routes
Just like our configuration variables, let’s move our routes into their own files. Create a folder called app/routes/and a file calledapp/routes/api.js.
When creating new files, we will have torequire()anything that is needed by that file. In our case, we will needbody-parser, ourUsermodel, ourconfigfile for thesecret, andjsonwebtokensince those were used in our routes.
We will also need app and express but we will be passing those into our routes since we want our application to use the sameappobject we create inserver.js. Let’s take a look at how we’ll structure our routes/api.jsfile that holds all of our API routes. Go into your existing ‘server.js’
file from chapter 10 and grab out all of the route code, starting at ‘var apiRouter = express.Router();’.
We will be wrapping this in our module.exports so that it can be passed between our javascript files.
Also take note of the changes to our variable superSecret and the packages we are including at the top.
1 var User = require('../models/user');
2 var jwt = require('jsonwebtoken');
3 var config = require('../../config');
4
5 // super secret for creating tokens 6 var superSecret = config.secret;
7
8 module.exports = function(app, express) { 9
10 var apiRouter = express.Router();
11
12 // route to authenticate a user (POST http://localhost:8080/api/authenticate)
MEAN Stack Application Structure 141 13 apiRouter.post('/authenticate', function(req, res) {
14 console.log(req.body.username);
15
16 // find the user
17 // select the password explicitly since mongoose is not returning it by defa\
18 ult
19 User.findOne({
20 username: req.body.username
21 }).select('password').exec(function(err, user) { 22
23 if (err) throw err;
24
25 // no user with that username was found 26 if (!user) {
27 res.json({
28 success: false,
29 message: 'Authentication failed. User not found.'
30 });
31 } else if (user) {
32
33 // check if password matches
34 var validPassword = user.comparePassword(req.body.password);
35 if (!validPassword) {
36 res.json({
37 success: false,
38 message: 'Authentication failed. Wrong password.'
39 });
40 } else {
41
42 // if user is found and password is right
43 // create a token
44 var token = jwt.sign(user, superSecret, { 45 expiresInMinutes: 1440 // expires in 24 hours
46 });
47
48 // return the information including token as JSON
49 res.json({
50 success: true,
51 message: 'Enjoy your token!',
52 token: token
53 });
54 }
55
61 // route middleware to verify a token 62 apiRouter.use(function(req, res, next) { 63 // do logging
64 console.log('Somebody just came to our app!');
65
66 // check header or url parameters or post parameters for token
67 var token = req.body.token || req.query.token || req.headers['x-access-token\
68 '];
69
70 // decode token 71 if (token) { 72
73 // verifies secret and checks exp
74 jwt.verify(token, superSecret, function(err, decoded) {
75 if (err) {
76 return res.json({ success: false, message: 'Failed to authenticate tok\
77 en.' });
78 } else {
79 // if everything is good, save to request for use in other routes 80 req.decoded = decoded;
81
82 next(); // make sure we go to the next routes and don't stop here
83 }
89 // return an HTTP response of 403 (access forbidden) and an error message
90 return res.status(403).send({
91 success: false,
92 message: 'No token provided.'
93 });
94
95 }
96
MEAN Stack Application Structure 143 97 });
98
99 // test route to make sure everything is working 100 // accessed at GET http://localhost:8080/api 101 apiRouter.get('/', function(req, res) {
102 res.json({ message: 'hooray! welcome to our api!' });
103 });
104
105 // on routes that end in /users
106 // ---107 apiRouter.route('/users')
108
109 // create a user (accessed at POST http://localhost:8080/users) 110 .post(function(req, res) {
111
112 var user = new User(); // create a new instance of the User model 113 user.name = req.body.name; // set the users name (comes from the requ\
114 est)
115 user.username = req.body.username; // set the users username (comes f\
116 rom the request)
117 user.password = req.body.password; // set the users password (comes f\
118 rom the request) 119
120 user.save(function(err) {
121 if (err) res.send(err);
122
123 // return a message
124 res.json({ message: 'User created!' });
125 });
126
127 })
128
129 // get all the users (accessed at GET http://localhost:8080/api/users) 130 .get(function(req, res) {
131 User.find(function(err, users) {
132 if (err) res.send(err);
133
134 // return the users
135 res.json(users);
136 });
137 });
138
139 // on routes that end in /users/:user_id
145 User.findById(req.params.user_id, function(err, user) {
146 if (err) res.send(err);
147
148 // return that user
149 res.json(user);
150 });
151 })
152
153 // update the user with this id 154 .put(function(req, res) {
155 User.findById(req.params.user_id, function(err, user) { 156
157 if (err) res.send(err);
158
159 // set the new user information if it exists in the request 160 if (req.body.name) user.name = req.body.name;
161 if (req.body.username) user.username = req.body.username;
162 if (req.body.password) user.password = req.body.password;
163
164 // save the user
165 user.save(function(err) {
166 if (err) res.send(err);
167
168 // return a message
169 res.json({ message: 'User updated!' });
170 });
171
172 });
173 })
174
175 // delete the user with this id 176 .delete(function(req, res) {
177 User.remove({
178 _id: req.params.user_id
179 }, function(err, user) {
180 if (err) res.send(err);
MEAN Stack Application Structure 145
181
182 res.json({ message: 'Successfully deleted' });
183 });
184 });
185
186 return apiRouter;
187 };
If you look carefully, you’ll see this doesn’t differ too much from how our code looked inserver.js. The main difference is that we are requiringconfig.jsand usingconfig.secret.
We are also passing back a function into module.exports and requiring that app and express are passed in. This is so we can use theexpress object to get an instance of express.Router();. Currently, we are not using theappobject, but it note that if you are not using the express.Router(), you could directly specify routes on theappobject as well.
We will thenreturn apiRouter;so that we can use it inserver.js.
Now that this file is created, we just need to call it inserver.js. This is where we can see just how clean our main file has become and how much easier it is to read than before.
These are the lines to use inserver.jswhen calling our newly created routes file:
1 // API ROUTES
---2 var apiRoutes = require('./app/routes/api')(app, express);
3 app.use('/api', apiRoutes);
If you didn’t do it earlier, go through and remove those routes and calls to packages that we moved into ourapi.jsfile. And that’s it! Now we have moved about 170 lines of code out of ourserver.js!