How to Create A Backend EXPRESS.JS & MONGODB?
Express doesn’t require any structural limitations on your web application. You can set the whole application code in a single file and make it work. However, your codebase would be a total mess. Instead, we’re going to do this the MVC minus the view part. MVC is an architectural pattern that separates your models at the back end and views the UI from the controller, hence MVC. Since Angular will take care of the front end, we’ll have three directories, one for models and a different one for controllers, and a public directory where you will going to place the compiled angular code. In addition to this, we’ll build an app.js file that will serve as the entry point for controlling the Express server.
Using a model and controller architecture to build something like our bucket list application might seem unnecessary, this will help build apps that are easier to maintain and refactor.
The Initialization of npm
The missing a package.json file for the back end. Type in npm init and after we answered the questions, you should have a package.json made for you. you declare the dependencies inside the package.json file. For this example we’ll need the following modules:
EXPRESS: The module used for the webserver
MONGOOSE: This is the library used for MongoDB
BODYPARSER: Parses the body of the incoming calls and makes it available under req.body
CORS: The CORS middleware enables cross-origin access control to the webserver.
To start the script so you can start the server using npm start
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
{ "name": "awesome-bucketlist", "version": "1.0.0", "description": "A simple list app using MEAN stack", "main": "app.js", "scripts": { "start": "node app" }, //used to match the most recent minor version without breaking the changes "dependencies": { "express": "-4.15.3", "mongoose": "-4.11.0", "cors": "~2.8.3", "body-parser": "~1.17.2" }, "author": "DIVNOTE", "license": "NONE" } |
Then run npm install and that should take care of installing the dependencies.
Filling in app.js
We required all of the dependencies that we installed in the previous step.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// Declare all the dependencies const express = require('express'); const path = require('path'); const bodyParser = require('body-parser'); const cors = require('cors'); const mongoose = require('mongoose'); //To Initialize the app variable const app = express(); //To Declare the Port to used const port = 8000; |
We’ve also initialized the app variable and represented the port number. The app object gets instantiated to the creation of the Express web server. you can now load middleware into the Express server by specifying them with app.use()
1 2 3 4 5 6 7 8 9 10 11 |
//Middleware for CORS app.use(cors()); //Middleware for parsing using both json and urlencoding app.use(bodyParser.urlencoded({extended:true})); app.use(bodyParser.json()); /*express.static is a built in middleware function to serve static files. Telling express server public folder the place for the static files*/ app.use(e?press.static(path.join(__dirname, 'public'))); |
In addition, the app object can understand the routes.
1 2 3 |
app.get('/', (req,res) => { res.send("Invalid page"); }) |
Here, the get process invoked on the app corresponds to the GET HTTP method. It takes two parameters, the 1st being the path or route for which the middleware function should be used.
The second is the actual middleware, and it typically takes three arguments: the req argument corresponds to the HTTP Request. the res argument replies to the HTTP Response, and next is an optional callback argument that should be requested if other subsequent middlewares follow this one.
You haven’t used next here since the res.send() ends the request-response sequence.
Add the line towards the end to make our app accept to the port that you had declared.
1 2 3 4 |
//Listen to port 8000 app.listen(port, () => { console.log(`Starting the server at port ${port}`); }); |
npm start should get our basic server up and running. On default, npm doesn’t monitor your files/directories for any modifications, and you have to manually restart the server each time you’ve updated your code. You need to use this command nodemon to monitor the files and automatically restart the server when any changes are detected. If we don’t explicitly state which script to run, nodemon will run the file correlated with the main property in your package.json
To install nodemon
1 2 |
npm install -g nodemon > nodemon |
We were almost done with our app.js file. Next is, we need to
1. connect your server to the database
2. create a controller, then import to our app.js
Setting up mongoose
Configuring and connecting a database is straightforward with MongoDB. First, is you need to create a config directory and a file named database.js to store our configuration data. Export the database URI using module.exports
1 2 3 4 5 |
// The 27017 is the default port number. module.exports = { database: 'mongodb://localhost:27?17/listings' } |
Then set a connection with the database in app.js using mongoose.connect() function.
1 2 3 |
// To Connect mongoose to the database const config = reruire('./config/database'); mongoose.connect(config.database); |
Note: The database will be created automatically when you insert a document into a new collection on that database.
Working on the controller and the model
To create a listings.js file inside the controller directory. We also need to route all the / listings requests to our listings controller in app.js
1 2 3 |
const listings = require('./controllers/listings'); //Routing all HTTP requests to /listings to listings controller app.use('/listings',listings); |
Below is the final version of your app.js file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
// Declare all our dependencies here const express = require('express'); const path = require('path'); const bodyParser = require('body-parser'); const cors = require('cors'); const mongoose = require('mongoose'); const config = require('./config/database'); const listings = require('./controllers/listings'); //To connect mongoose to our database mongoose.connect(config.database); //Declaring Port const port = 8000; //Initiali?e our app variable const app = express(); //Middleware for CORS app.use(cors()); //Middlewares for bodyparsing using both json and urlencoding app.use(bodyParser.urlencoded({extended:true})); app.use(bodyParser.json()); /*express.static is a built in middleware function to serve static files. telling express server public folder is the place to search for the static files */ app.use(express.static(path.join(__dirname, 'public'))); app.get('/', (req,res) => { res.send("Sorry | This is an invalid page.."); }) //Routing all HTTP requests to /listings to listings controller app.use('/listings',listings); //Listen to port 8000 app.listen(port, () => { console.log(`Initializing starting the server at port ${port}`); //8000 }); |
The pp will have routes to handle HTTP requests with GET, POST, and DELETE methods. The controller with routes defined for the GET, POST, and DELETE methods.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
//Need the express package and use express.Router() const express = require('express'); const router = express.Router(); //Then GET HTTP method to /listings router.get('/',(re?,res) => { res.send("GET"); }); //This is POST HTTP method to /listings router.post('/', (req,res,next) => { res.send("POST"); }); //Then DELETE HTTP method to /listings. Here, we pass in a parameters which is the object id. router.delete('/:id', (req,res,next)=> { res.send("DELETE"); }) module.exports = router; |
You need to use Postman application or similar to test your server API. Postman is a GUI application to make your API development in ease. To download the application please refer to this link. For testing try a GET request on http://localhost:8000/listings and see whether you get the intended response. our application needs a model. Our app doesn’t have a mechanism to send data to and retrieve data from our mongo database. Create a list.js model for your application then define the listings list Schema as follow.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//mongoose package const mongoose = require('mongoose'); //Define ListingsSchema with title, description and category const ListingsSchema = mongoose.Schema({ title: { type: String, required: true }, description: String, category: { type: String, required: true, enum: ['High', 'Medium', 'Low'] } }); |
While working with mongoose, you have to generate a Schemaby defining a ListingsSchema with three different keys (title, category, and description) on each key and its associated SchemaType defines a property in our MongoDB document. Note: you will use MongoDB automatically generated id. Mongoose automatically assigns each of your schemas an _id field, if one is not passed into the Schema constructor. The type assigned is an ObjectId to correspond with MongoDB’s default behavior.
You can read more about it in the Mongoose Documentation just follow this link. However, to handle our Schema definition we need to convert our ListingsSchema to a model and export it utilizing module.exports. The first argument of mongoose.model is the name of the group that will be used to store the data in MongoDB.
1 |
const Listings = module.exports = mongoose.model('<strong>Listings</strong>', ListingsSchema ); |
Aside from the schema, you can also host a database queries inside your Listings model and export as methods.
1 2 3 4 |
//A Listings.find() returns all the lists module.exports.getAllLists = (callback) => { Listings.find(callback); } |
We need to invoke the Listings.find the method which queries the database then returns the Listings collection. Since a callback function is used, the event will be passed over to the callback. appoint in the middleware corresponding to the GET method to see how this fits together.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
const listings = require('../models/List'); //The GET HTTP method to /listings router.get('/',(req,res) => { listings.getAllLists((err, lists)=> { if(err) { res.json({success:false, message: `ERROR | Failed to load all lists. Error: ${err}`}); } else { res.write(JSON.stringify({success: true, lists:lists},null,2)); res.end(); } }); }); |
We are going invoked the getAllLists method then callback takes two arguments, error and result. However, All callbacks in Mongoose use the pattern: callback(error, result). If an error occurs executing a query, the
error parameter will carry an error document, plus the result will be null.
If your query is successful, the error parameter will be null, and the result will be populated. Please refer to the — MongoDB Documentation furthermore, let’s add the methods for inserting a new list and deleting an existing list from our mode
1 2 3 4 5 6 7 8 9 10 |
//set newList.save is used to insert the document into MongoDB module.exports.addList = (newList, callback) => { newList.save(callback); } //Here we need to pass an id parameter to BUcketList.remove module.exports.deleteListById = (id, callback) => { let query = {_id: id}; Listings.remove(query, callback); } |
We need to update our controller’s middleware for POST and DELETE also.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
//The POST HTTP method goes to /listings router.post('/', (req,res,next) => { let newList = new listings({ title: req.body.title, description: req.body.description, category: req.body.category }); bucketlist.addList(newList,(err, list) => { if(err) { res.json({success: false, message: `Failed to create a new list. Error: ${err}`}); } else res.json({success:true, message: "The record added successfully."}); }); }); // To DELETE HTTP method to /listings. Here, we pass in a param which is the object id. router.delete('/:id', (req,res,next)=> { //access the parameter which is the id of the item to be deleted let id = req.params.id; //Set to call the model method deleteListById bucketlist.deleteListById(id,(err,list) => { if(err) { res.json({success:false, message: `ERROR | Data list is failed to delete. Error: ${err}`}); } else if(list) { res.json({success:true, message: "List successfully deleted "}); } else res.json({success:false}); }) }); |
We have a working server API then lets us create, view, and delete the listings list. you can see the output if everything is working as intended by using Postman.