Here is a series of articles that will allow you to create backend applications with NodeJS + Express.
This series is the continuation of my series on the basics of NodeJS. If you don't have basic knowledge of NodeJS read this series first: Introduction to NodeJS
Node.js is today a must, so it is essential for a developer to master it.
So I will publish a new article about every two days and little by little you will learn everything there is to know about Node.js + Espress
To not miss anything follow me on twitter: https://twitter.com/EricTheCoder_
MongoDB Database
In this section we will learn how to manipulate a MongoDB database from our API.
You probably know that there are several types of databases such as SQL databases and NoSQL databases.
The purpose of this article is not to explain in detail what a database is and how it works internally. So a minimum of database knowledge is required.
Today we are going to use MongoDB which is a NoSQL database
NoSQL databases contain collections that contain documents. For example a database could have the User collection and several documents which would each contain the information of a user such as for example: no, last name, first name, etc.
If you have experience with SQL databases, we could simplify this by saying that collections are tables and documents are rows and columns of tables.
MongoDB installation
MongoDB can be installed on your local machine or be used as a cloud database version.
In this tutorial we will create a MongoDB database from their cloud. https://www.mongodb.com/atlas
The service is free and does not require a credit card.
To have access to the MongoDB cloud and then be able to create your own database, go to https://www.mongodb.com/atlas and click on the "Try Free" button.
Choose the Atlas service, complete the questionnaire and click "Get started free"
Once your account is created, go to the control panel, you should see something like this.
Click on "Build a Database", then choose the "Free Shared" option and click on "Create". Then keep the default options except the last option which is "Cluster Name" and change the name to "NodeExpress". Finally click on "Create Cluster"
Create a database
Your MongoDB account is created and activated we will now create our database and our first collection
With your cluster now created, you should see something like this
To create a database and a collection. Click on "Browse Collection", then on "Add My Own Data". Finally enter the name of the database and the name of the collection and click on "Create"
Ready to code
To sum up, we created a MongoDB cloud account, created a free Cluster and created our first "Demo" database and finally our first "Products" collection.
Now we are ready to code our API and manipulate our database
Creation of the NodeJS project
We are now going to create our NodeJS project, I will give here the starting code (which comes from the previous articles).
Create a folder
$ mkdir demo-express-mongo
$ cd demo-express-mongo
Then install the ExpressJS package and nodemon
$ npm install express
$ npm nodemon
Note that as specified in the section on NodeJS, the nodemon package allows you to reload the server each time our code is modified.
In order not to repeat the concepts that we covered in the previous articles, we will start with the same code that we had at the end of the last article.
Create a controllers folder and create a products.js file with the following code
const products = require('../data.js')
const getProducts = ((req, res) => {
res.json(products)
})
const getProduct = ((req, res) => {
const id = Number(req.params.productID)
const product = products.find(product => product.id === id)
if (!product) {
return res.status(404).send('Product not found')
}
res.json(product)
})
const createProduct = ((req, res) => {
const newProduct = {
id: products.length + 1,
name: req.body.name,
price: req.body.price
}
products.push(newProduct)
res.status(201).json(newProduct)
})
const updateProduct = ((req, res) => {
const id = Number(req.params.productID)
const index = products.findIndex(product => product.id === id)
const updatedProduct = {
id: products[index].id,
name: req.body.name,
price: req.body.price
}
products[index] = updatedProduct
res.status(200).json('Product updated')
})
const deleteProduct = ((req, res) => {
const id = Number(req.params.productID)
const index = products.findIndex(product => product.id === id)
products.splice(index,1)
res.status(200).json('Product deleted')
})
module.exports = {
getProducts,
getProduct,
createProduct,
updateProduct,
deleteProduct
}
Then, create a "routes" folder and create the products.js file
const express = require('express')
const router = express.Router()
const {
getProducts,
getProduct,
createProduct,
updateProduct,
deleteProduct
} = require('../controllers/products.js')
router.get('/', getProducts)
router.get('/:productID', getProduct)
router.post('/', createProduct)
router.put('/:productID', updateProduct)
router.delete('/:productID', deleteProduct)
module.exports = router
Finally, create an app.js file with the following code
const express = require('express')
const app = express()
const products_routes = require('./routes/products.js')
app.listen(5000, () => {
console.log('server is listening on port 5000')
})
app.use(express.json())
app.use('/api/products', products_routes)
So far nothing new, we are ready to continue this code by adding our MongoDB database
fichier .env
To connect to our MongoDB database we need the connection URL. MongoDB will provide us with this URL. The thing is, for obvious security reasons, we can't use this login URL directly in our code.
The connection URL must be placed in a file that will be out of reach of users during deployment.
To do this we will therefore create a file that will contain our connection URL. By convention this file named ".env" (dot env)
You can create this file at the root of the project and include the MongoDB connection URL
// .env
MONGO_URI = 'mongodb+srv://<username>:<password>@nodeexpress.my1j7.mongodb.net/myFirstDatabase?retryWrites=true&w=majority'
To get your MongoDB login URL. Connect to your MongoDB cloud account and from the "Databases" menu click on "Connect", then choose the "Connect you application" option
MongoDB will show you your connection string, copy it and paste it into your .env file
In the connection string, replace and with your username and password MongoDB cloud user and also replace "myFirstDatabase" with the name of your database (ie "demo")
Communicating with MongoDB from NodeJS
There are several ways to communicate with your MongoDB database. For this project I decided to use the NodeJS package named "mongoose"
This packages makes it easy to link MongoDB and your API.
ODM
mongoose is an ODM (Object Document Mapping) which means that mongoose allows you to create an object (called a model) to represent and manipulate each of our collections.
This object (model) will contain several pre-defined functions that will allow you to easily handle the collection associated with this object.
Once the model is created, no need to manipulate the database, just use the methods of the model object and it will take care of communicating to the database. Suddenly, this pattern significantly increases the ease of handling the database.
Here is a quick example to visualize the concept
const products = await Product.find({})
In this code, the "Product" object / model uses the "find" method in order to read all the documents in the collection. The documents retrieved are sent to the "products" variable.
Creation of a mongoose model
We are now going to create a "Product" object / model
The first step is to install the mongoose package```jsx
npm install mongoose
npm install dotenv
While we are there we will also install the dotenv package. This package allows you to read the ".env" config file that we created earlier and load its variables into the current process.
Once the package is used, we can create our first mongoose model.
Create a "models" folder and create the Product.js file
```jsx
const mongoose = require('mongoose')
const ProductSchema = new mongoose.Schema({
name:String,
price: Float,
})
const Product = mongoose.model('Product', ProductSchema)
module.exports = Product
Mongoose models are created from the diagrams.
The diagram is used to define the structure of a document. (Kind of like the columns of a table in an SQL database).
In the last example we define the Product schema which will be the structure of the documents of the Products collection
The penultimate line allows you to create the Product model from the diagram
const Product = mongoose.model('Product', ProductSchema)
Connection to the database
Now that we have a mongoose model to work with, we must now establish the connection between mongoose and our MongoDB database.
Modify the app.js file to include the database connection code.
const express = require('express')
const mongoose = require('mongoose')
const app = express()
const products = require('./data.js')
const products_routes = require('./routes/products.js')
require('dotenv').config()
mongoose.connect(process.env.MONGO_URI)
.then((result) => app.listen(5000))
.catch((err) => console.log(Error))
app.use(express.json())
app.use('/api/products', products_routes)
Let's go back to the code with some explanations:
Send the contents of the .env file to the process.env object
require('dotenv').config()
Use the MONGO_URL to create a connection with your database
mongoose.connect(process.env.MONGO_URI)
If the connection is successful then start the NodeJS server otherwise display the error.
mongoose.connect(process.env.MONGO_URI)
.then((result) => app.listen(5000))
.catch((err) => console.log(Error))
CRUD API
Now that we have our connection to MongoDB, we can modify our "products" controller file (/controllers/products.js) and add the Product model methods to it.
In fact the operation of these methods is so simple and explicit that we do not need to explain them.
const Product = require('../models/Product.js')
const getProducts = ((req, res) => {
Product.find({})
.then(result => res.status(200).json({ result }))
.catch(error => res.status(500).json({msg: error}))
})
const getProduct = ((req, res) => {
Product.findOne({ _id: req.params.productID })
.then(result => res.status(200).json({ result }))
.catch(() => res.status(404).json({msg: 'Product not found'}))
})
const createProduct = ((req, res) => {
Product.create(req.body)
.then(result => res.status(200).json({ result }))
.catch((error) => res.status(500).json({msg: error }))
})
const updateProduct = ((req, res) => {
Product.findOneAndUpdate({ _id: req.params.productID }, req.body, { new: true, runValidators: true })
.then(result => res.status(200).json({ result }))
.catch((error) => res.status(404).json({msg: 'Product not found' }))
})
const deleteProduct = ((req, res) => {
Product.findOneAndDelete({ _id: req.params.productID })
.then(result => res.status(200).json({ result }))
.catch((error) => res.status(404).json({msg: 'Product not found' }))
})
module.exports = {
getProducts,
getProduct,
createProduct,
updateProduct,
deleteProduct
}
However, if you want to know in detail how these methods work and the other methods available, see the mongoose documentation here: https://mongoosejs.com/docs/models.html
Test your API
You can now launch the Node.JS server and test the API
$ npx nodemon app.js
The server will be launched on port 5000 accessible to localhost: 5000
Using software like Postman, you can now test your API with the following queries:
GET localhost:5000/api/products
GET localhost:5000/api/product/<id>
POST localhost:5000/api/products
PATCH localhost:5000/api/products/<id>
DELETE localhost:5000/api/products/<id>
Note that for POST and PATH actions, you must send them with content in the body section of your request. Here is an example of content in JSON:
{
"name": "iPhone12",
"price": 899
}
Conclusion
That's all for today, follow me on twitter: https://twitter.com/EricTheCoder_ to be notified of the publication of the next article (within two days).
Top comments (4)
Thank you!
Notes:
I received an error with the word "Float" at /models/Product.js so I replaced it with "Number"
I am also currently having an error: [Function: Error] { stackTraceLimit: 10, prepareStackTrace: undefined } and I will update if I know how to solve the issue.
@ashlee380518 Did you solve the error?
Thank you. Easy to read with good examples.
Many thanks for this outstanding piece