« Previous Tutorial Next Tutorial »

Everyone ready to dive back into the murky waters of API development? Don’t worry, this part’s going to be pretty straightforward. We’re going to nuke our users database (more on that in a second), install an app to help us send test POST data since we don’t have a front-end yet, build an API endpoint to register users, and test it with the app. Sounds like a lot, right? Well, it kind of is, let’s get going!

First off, remember back in Tutorial 18 when we created a test user with a plaintext password, and I advised you to never, ever store your passwords in plaintext and assured you that the only reason we were doing it was for a test, and that the user would soon be nuked? Well, it’s now “soon” so open your mongo console by heading to a terminal window or command prompt and typing

mongo

and then type the following two commands:

use musiclist
db.users.remove({})

This will blank out your users database entirely, no matter how full it is, so as always, be careful with this command (and really, be careful any time you direct-edit your database).

OK, you can close mongo and switch over to, well, a web browser. Point it to postman.com and snag a version of the software that’s best suited to your OS. Postman allows you to send HTTP requests to a given URI, with a high degree of control over what you’re putting into your headers, body, and so forth. We’re barely going to scratch its surface right now, but that’s fine. It’ll keep things simple.

This install is so fast on both OS’s that I’m just going to cover both real quick. Here we go!

OSX users: open the download, which will unzip it to your downloads folder (or wherever you saved it). Drag the unzipped application to your applications folder. Add to the dock if you particularly feel like it, or just run it from Launchpad. Your call! You can create a login if you'd like, once it's running. I didn't bother.

Windows users: open the download, run the installer, and then postman will auto-start it at the end of the install. Again, no login needed, but it’s your call. Obviously, when you want to use it later, you can find it in your start menu’s application list.

OK, let’s write some API endpoints. Oh, and we need to make one quick change to our User model, too. When we created it, I totally blanked on including an email address, which is … kind of important! Let’s do that real quick. Open /models/user.js and, under line 10, add the following:

  email: String,

That’s it. Take a moment to remember that we previously added some Passport connectivity to this model, which is shortly going to allow us to use Passport’s register method. Then save this file, and move on.

Under /routes/api, create a file called authentication.js. This is going to hold all of our auth-related endpoints, including registering, so let’s start with that, since right now we don’t have anyone in the database. Let’s start with these three lines:

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

Here we’re requiring Express, Passport, and our user model. Quick recap on Passport: it’s a fantastic authentication module for Express that saves us the headache of having to handle that stuff ourselves. We installed it back in Tutorial 17, but haven’t really touched it since then. That changes now!

Below line 3, add a blank line and then, on line 5, this code:

const router = express.Router();

Add a little more whitespace, and let’s define our route on line 7, like this:

// POST to /register
router.post('/register', (req, res) => {
});

Obviously that’s not doing much yet. It just tells our app to listen for a POST to /register (underneath the rest of our API URI, which we’ll define in a minute). Now, let’s use the incoming JSON data and create a user object to save, via our User model (which we use to make sure that only the data we want in our database gets in there, in case the JSON being sent contains excess stuff). Here’s the code for that:

// POST to /register
router.post('/register', (req, res) => {
  // Create a user object to save, using values from incoming JSON
  const newUser = new User({
    username: req.body.username,
    firstName: req.body.firstName,
    lastName: req.body.lastName,
    email: req.body.email,
  });
});

req.body, by the way, will contain all of our incoming JSON data (or form data, if we were sending this via a normal web form, but we’ll be using Ajax to send it as JSON).

OK, we have a user object to save. Let’s save it, like this:

// POST to /register
router.post('/register', (req, res) => {
  // Create a user object to save, using values from incoming JSON
  const newUser = new User({
    username: req.body.username,
    firstName: req.body.firstName,
    lastName: req.body.lastName,
    email: req.body.email,
  });

  // Save, via passport's "register" method, the user
  User.register(newUser, req.body.password, (err, user) => {
    // If there's a problem, send back a JSON object with the error
    if (err) {
      return res.send(JSON.stringify({ error: err }));
    }
    // Otherwise, for now, send back a JSON object with the new user's info
    return res.send(JSON.stringify(user));
  });
});

Passport’s register is great. It creates a salted hash of the user’s password, which means we only ever store that hash (and the salt), which is an added layer of security. It means that in the event your database is compromised, attackers only get a massive, encrypted string, and not the password. If you tried to send that string as a password, Passport won’t recognize it, because it’s expecting a plaintext password which then gets encrypted and compared to the hash. If you encrypt the already-encrypted string, you get a new, totally different hash. Combine this with HTTPS and you’ve got a very secure method of registration and login. Nice.

We’re almost done. We need one final line at the end of our file:

module.exports = router;

This will allow us to use these new API routes in app.js. Your entire file, for reference, should look like this:

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

const router = express.Router();

// POST to /register
router.post('/register', (req, res) => {
  // Create a user object to save, using values from incoming JSON
  const newUser = new User({
    username: req.body.username,
    firstName: req.body.firstName,
    lastName: req.body.lastName,
    email: req.body.email,
  });

  // Save, via passport's "register" method, the user
  User.register(newUser, req.body.password, (err, user) => {
    // If there's a problem, send back a JSON object with the error
    if (err) {
      return res.send(JSON.stringify({ error: err }));
    }
    // Otherwise, for now, send back a JSON object with the new user's info
    return res.send(JSON.stringify(user));
  });
});

module.exports = router;

All right, save this file and move on to app.js. We need two lines, here. First, underneath line 24, add the following:

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

Second, underneath line 62, add this code:

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

As you can see, the first line brings our authentication router into the app, and the second line says to direct any requests to /api/authentication to it. Thus, it will currently handle /api/authentication/register. Any other requests will currently redirect back to the top level of our server, initializing our react app (for example, if you tried localhost:3000/api/authentication/test you’d just end up seeing our Musiclist header with no page content). That’s all for app.js. Save the file, and it’s time to create a user and then log him in.

The following section contains instructions for using software, which is always kinda dicey in text. If you’re having trouble, I strongly encourage you to check out the video

Switch over to postman, and set the dropdown that currently says “GET” to post. In the URI box directly to the right of that dropdown, type http://localhost:3000/api/authentication/register. Just under that box, click the word “body,” check the radio button for “raw,” and change the dropdown at the right end of the line to “JSON (application/json)” … phew. OK, we’re ready to POST, except we need to send some actual data! So, in the big text box, type this:

{
  "username": "administrator",
  "password": "WHATEVERPASSWORDYOUWANT",
  "firstName": "YOURFIRSTNAME",
  "lastName": "YOURLASTNAME",
  "email": "YOURPREFERREDEMAIL"
}

Obviously, all that stuff in caps should be replaced with whatever you want. For example, mine looks like this:

{
  "username": "administrator",
  "password": "correcthorsebatterystaple",
  "firstName": "Christopher",
  "lastName": "Buecheler",
  "email": "noreply@closebrace.com"
}

Though of course I don’t use that password in anything. Pick a good, strong, secure password, even though you’re testing. It’s just the right way to go.

All right … press the big blue Send button and let’s see what happens. You should get a server response containing your brand new user object, including the hashed password. Awesome! You can haz user registration.

Next up, we’ll build and test an endpoint for logging the user in (and out). See you soon!

« Previous Tutorial Next Tutorial »