« Previous Tutorial Next tutorial »

When last we left off, we had a test that was failing because we hadn’t actually written the code necessary to create the API endpoint the test was supposed to be testing. This was intentional. Now we’re going to write the code that will allow the test to succeed.

You should still have MongoDB and your Express server running from the last tutorial. If you don’t, make sure to launch ‘em. Switch over to Sublime Text (or your editor of choice) and let’s create a new file in /routes/api called users.js – we’ll use this to handle API endpoints that deal with users and user accounts. In a larger application, you’d probably want to break this out into even more granular chunks, but we shouldn’t need to do that here (and if we do, it can be done later with relative ease).

We’ll start our router file as we’ve started others in previous examples:

const express = require('express');
const router = express.Router();

Nothing’s changed here – all of our route files are going to start this way. But now we need to require something else: our User model. So add this line:

const User = require('../../models/user');

Mongoose models aren’t just for saving data, they’re also used to retrieve it. By convention, a Mongoose model is automatically tied to its plural in your database. We manually created the users collection, but if we hadn’t, Mongoose would’ve created it the first time we saved a User. Similarly, if we were to create a Mongoose model called “Post” and save a post, the resulting collection in our database would be “posts” … this is important to know, since it can help you avoid using Model names which would result in weird of irregular plurals. For example, a “Fish” model would result in a collection named “Fishs,” which isn’t really what you’re looking for. You can, however, override this behavior and force the collection to be named in a way you want.

In our case, we’re already all set, so let’s move on.

Next up, we want to set up our API to listen for requests at /api/users/list … we’ll handle the first two folders in app.js. In this file, we only need to worry about the final directory. Add these lines:

router.get('/list', (req, res, next) => {
});

This is a standard Express router statement. It’s just saying, “when we request /list” (which, again, we’ll prepend with /api/users in a minute), do something. So let’s make it do something. Inside that function, add these lines:

  User.find((err, users) => {
    if (err) {
      res.send(err);
    }
    res.json(users);
  });

So your full function should now look like this:

router.get('/list', (req, res, next) => {
  User.find((err, users) => {
    if (err) {
      res.send(err);
    }
    res.json(users);
  });
});

OK, so, it’s a little weird to be using a singular model name to find potentially more than one user, but think of it like saying “find ANY user that matches X” … in this case we’re not providing X, so the result will be every single user. Mongoose has a convenient FindOne method that’ll allow you to get a single object returned, although this can be problematic depending on what you’re searching for; if you have three users with a first name of “Jim” and that’s what you search for, you’ll only ever get back to first one if you use FindOne.

Anyway, this code will get us all users, which is what we want. Just add one more line at the bottom of the file:

module.exports = router;

So our completed file should look like this (I’ve added a few comments):

const express = require('express');
const router = express.Router();

// Import our User model
const User = require('../../models/user');

// GET User List.
router.get('/list', (req, res, next) => {

  // Find all matching users, which in this case is all of 'em
  User.find((err, users) => {
    if (err) {
      // if something's broken, send an error
      res.send(err);
    }
    // Otherwise, send the array of users.
    res.json(users);
  });
});

module.exports = router;

Now we need to make a quick change to app.js to point to our new endpoint. Save this file and open app.js. Find these two lines:

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

and below them add:

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

Then find these two lines:

app.use('/', index);
app.use('/api', api);

And below them add the following:

app.use('/api/users', users);

Save that file and we’re set. Our test should pass. Let’s do a sanity check and look at the API output in a browser, too. If you ran nodemon to start your server, it should’ve restarted several times as you saved various JS files. Head to http://localhost:3000/api/users/list and you should see JSON output of the single user we’ve created. Cool!

Now open up a new terminal window or command prompt, cd to your musiclist directory, and let’s run the same test that produced that big error before by typing:

yarn test

Here’s what we get now:

PASS  routes\api\users.test.js
  The User API
    √ Returns a list of all users (55ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.508s
Ran all test suites.

Muuuch better. We’re all set here. We’ve built an API endpoint and tested it. We’ll need to do some work to lock it down, but that can wait a bit. In the next tutorial, we’re going to talk about linting our code. Until then!

« Previous Tutorial Next tutorial »