NodeJS + MongoDB
NodeJS + MongoDB
After building a few front end tutorials and examples on user authentication with
Angular and React I thought I'd put together a simple custom backend api that can
be easily 'plugged in' to the front ends, or be easily hooked up with your own
custom client application.
The api is written in JavaScript for NodeJS and requires MongoDB to be running.
Mongoose is used to connect to MongoDB, define the database schema and read/write
data. Express is used as the web server.
Update History:
Below are instructions on how to use Postman to register a new user with the api,
authenticate a user to get a JWT token, and then make an authenticated request with
the JWT token to retrieve a list of users from the api.
Open a new request tab by clicking the plus (+) button at the end of the tabs.
Change the http request method to "POST" with the dropdown selector on the left of
the URL input field.
In the URL field enter the address to the register route of your local API -
http://localhost:4000/users/register.
Select the "Body" tab below the URL field, change the body type radio button to
"raw", and change the format dropdown selector to "JSON (application/json)".
Enter a JSON object containing the required user properties in the "Body" textarea,
e.g:
{
"firstName": "Jason",
"lastName": "Watmore",
"username": "jason",
"password": "my-super-secret-password"
}
Click the "Send" button, you should receive a "200 OK" response with an empty JSON
object in the response body.
Here's a screenshot of Postman after the request is sent and the new user has been
registered:
Open a new request tab by clicking the plus (+) button at the end of the tabs.
Change the http request method to "POST" with the dropdown selector on the left of
the URL input field.
In the URL field enter the address to the authenticate route of your local API -
http://localhost:4000/users/authenticate.
Select the "Body" tab below the URL field, change the body type radio button to
"raw", and change the format dropdown selector to "JSON (application/json)".
Enter a JSON object containing the username and password in the "Body" textarea:
{
"username": "jason",
"password": "my-super-secret-password"
}
Click the "Send" button, you should receive a "200 OK" response with the user
details including a JWT token in the response body, make a copy of the token value
because we'll be using it in the next step to make an authenticated request.
Here's a screenshot of Postman after the request is sent and the user has been
authenticated:
Open a new request tab by clicking the plus (+) button at the end of the tabs.
Change the http request method to "PUT" with the dropdown selector on the left of
the URL input field.
In the URL field enter the address to the /users/{id} route with the id of the user
you registered above, e.g - http://localhost:4000/users/1.
Select the "Authorization" tab below the URL field, change the type to "Bearer
Token" in the type dropdown selector, and paste the JWT token from the previous
authenticate step into the "Token" field.
Select the "Body" tab below the URL field, change the body type radio button to
"raw", and change the format dropdown selector to "JSON (application/json)".
Enter a JSON object in the "Body" textarea containing the properties you want to
update, for example to update the first and last names:
{
"firstName": "Foo",
"lastName": "Bar"
}
Click the "Send" button, you should receive a "200 OK" response with an empty JSON
object in the response body.
Here's a screenshot of Postman after the request is sent and the user has been
updated:
The example only contains the single users feature, but this can be easily extended
to handle any other feature by copying the users folder and following the same
pattern.
_helpers
db.js
error-handler.js
jwt.js
users
user.model.js
user.service.js
users.controller.js
config.json
server.js
Back to top
module.exports = {
User: require('../users/user.model')
};
Back to top
module.exports = errorHandler;
function errorHandler(err, req, res, next) {
if (typeof (err) === 'string') {
// custom application error
return res.status(400).json({ message: err });
}
JWT authentication is used on all routes except for the authenticate and register
routes which are public.
module.exports = jwt;
function jwt() {
const secret = config.secret;
return expressJwt({ secret, algorithms: ['HS256'], isRevoked }).unless({
path: [
// public routes that don't require authentication
'/users/authenticate',
'/users/register'
]
});
}
done();
};
Back to top
NodeJS Users Folder
Path: /users
The users folder contains all code that is specific to the users feature of the
api.
Back to top
schema.set('toJSON', { ... }); configures which user properties are included when
converting MongoDB records to JSON objects which are returned in API responses.
virtuals: true includes the Mongoose virtual id property which is a copy of the
MongoDB _id property.
versionKey: false excludes the Mongoose version key (__v).
transform: function (doc, ret) { ... } removes the MongoDB _id property and
password hash so they are not included in API responses.
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
schema.set('toJSON', {
virtuals: true,
versionKey: false,
transform: function (doc, ret) {
delete ret._id;
delete ret.hash;
}
});
The top of the file contains the service method definitions so it's easy to see all
methods at a glance, the rest of the file contains the method implementations.
module.exports = {
authenticate,
getAll,
getById,
create,
update,
delete: _delete
};
// hash password
if (userParam.password) {
user.hash = bcrypt.hashSync(userParam.password, 10);
}
// save user
await user.save();
}
// validate
if (!user) throw 'User not found';
if (user.username !== userParam.username && await User.findOne({ username:
userParam.username })) {
throw 'Username "' + userParam.username + '" is already taken';
}
// hash password if it was entered
if (userParam.password) {
userParam.hash = bcrypt.hashSync(userParam.password, 10);
}
await user.save();
}
Express is the web server used by the api, it's one of the most popular web
application frameworks for NodeJS.
// routes
router.post('/authenticate', authenticate);
router.post('/register', register);
router.get('/', getAll);
router.get('/current', getCurrent);
router.get('/:id', getById);
router.put('/:id', update);
router.delete('/:id', _delete);
module.exports = router;
IMPORTANT: The "secret" property is used by the api to sign and verify JWT tokens
for authentication, update it with your own random string to ensure nobody else can
generate a JWT to gain unauthorised access to your application.
{
"connectionString": "mongodb://localhost/node-mongo-registration-login-api",
"secret": "THIS IS USED TO SIGN AND VERIFY JWT TOKENS, REPLACE IT WITH YOUR OWN
SECRET, IT CAN BE ANY STRING"
}
Back to top
require('rootpath')();
const express = require('express');
const app = express();
const cors = require('cors');
const bodyParser = require('body-parser');
const jwt = require('_helpers/jwt');
const errorHandler = require('_helpers/error-handler');
// start server
const port = process.env.NODE_ENV === 'production' ? (process.env.PORT || 80) :
4000;
const server = app.listen(port, function () {
console.log('Server listening on port ' + port);
});
Back to top
ABOUT
I'm a web developer in Sydney Australia and the technical lead at Point Blank
Development, I've been building websites and web applications in Sydney since 1998.
Find me on:
MONTHS
2020
November (2)
October (16)
September (26)
August (5)
July (22)
June (5)
May (7)
April (17)
March (5)
February (6)
January (5)
2019
2018
2017
2016
2015
2014
2013
2012
2011
TAGS
Alerts Angular Angular 10 Angular 2 Angular 4 Angular 5 Angular 6 Angular 7 Angular
8 Angular 9 Angular Directive Angular UI Router AngularJS Animation ASP.NET ASP.NET
Core ASP.NET Web API Authentication and Authorization AWS Axios Azure Basic
Authentication Blazor Bootstrap C# Chai CKEditor CSS3 DDD Deployment Design
Patterns Dynamic LINQ EF Core ELMAH ES6 Exchange Facebook Fetch Fluent NHibernate
Formik Google Analytics Google API Google Maps API Google Plus Heroku HTML5 HTTP
IIS Insecure Content Instagram API Ionic Framework iOS iPhone JavaScript jQuery JWT
LinkedIn LINQ Login MEAN Stack MERN Stack MEVN Stack Mocha Modal MongoDB Moq MVC
MVC5 MySQL NGINX ngMock NHibernate Ninject NodeJS npm Pagination Pinterest Razor
Pages React React Hooks Redmine Redux Registration Repository RxJS Security
Sequelize Shell Scripting Sinon SinonJS SSH TDD Terraform Twitter TypeScript Ubuntu
Umbraco Unit of Work Unit Testing URL Rewrite Validation Vue Vue 3 Vuex Webpack
Windows Server 2008
Powered by MEANie
© 2020 JasonWatmore.com
SPONSOR
Authentic Jobs — Your new development career awaits. Check out the latest listings.