Learn How to Build a Restful CRUD API using NodeJS, Express, and MongoDB
Create a CRUD API using nodeJS and connect it to a MongoDB database using mongoose.
Remi Gathoni
Introduction
CRUD stands for Create(Insert data to database), Read (Retrieve data from database), Update (Edit data from database), and Delete (delete data from database)
It is a
popular design through which Web APIs interact with databases.
This tutorial shows you how to:
- Set up an express server
- Set up routes with express
- Connect to MongoDB using Mongoose
- Write mongoose models
- Use Mongoose to make database queries
Prerequisites
- At least node 8.10 and npm >= 5.6
- Working knowledge of nodeJS
- JavaScript concepts like arrow functions, object destructuring, and async/await.
I am using Ubuntu 18.04 and a VS Code editor
Create a new folder
Open your terminal and create a new folder and move into it.
mkdir crud-api-nodejs && cd crud-api-nodejs
Initialize npm. You can change the options or you can accept the default options.
npm init -y
Create an Express Server
Install Express
npm i express
Create server.js and open VS Code
touch server.js
code .
In ./app.js, add the following code
// Require express
const express = require('express')
// Initialize express
const app = express()
// parse json objects
app.use(express.json())
// parse url encoded objects- data sent through the url
app.use(urlencoded({ extended: true}))
// create a server
const PORT = 8080
app.listen(PORT, () => {
console.log(`Server running on port ${PORT }`)
}
In the above code, we have,
- Added express to our app
- Initialized express
- Added options to parse JSON and URL encoded data.
- Started a server
Connect to database
In ./db.js
const mongoose = require('mongoose')
const dbURI = 'mongodb://localhost:27017/bookDb'
mongoose.connect(dbURI, {useNewUrlParser:true})
// connect to database
const db = mongoose.connection
// if error
db.on("error", (err) => {
console.error(`err: ${err}`)
})// if connected
db.on('connected', (err, res) => {
console.log('Connected to database')
})
Import ./db.js to ./server.js
const express= require('express')const app = express()
const db = require('./db')
.
.
.
Create Book Schema Model in ./bookSchema.js
const mongoose = require('mongoose')const bookSchema = mongoose.Schema({
title: {
type: String,
required: true
},
author: {
type: String,
required: true
},
publisher: {
type: String,
required: true
},
read: {
type: Boolean,
required: true
}
})
// Export modelmodule.exports = mongoose.model('Book', bookSchema)
Create
Here is what happens
- A client will send book info to our server through the request body.
- Check whether the data was actually sent, if not, send a bad request response
- Create a new record in the database
- If successful, send a 201 created response back
Let's first create a helper function for creating a database record
In ./dbHelpers.js add the following:
const Book = require('./bookSchema')exports.create = async (data) => {
try{
const newBook = new Book(data) const savedBook = newBook.save()
if(!savedBook) throw New Error()
return {error: null}
} catch (error) {
return {error: error.message}
}
}
Remember to import the helper function in ./server.js
const { create } = require('./dbHelpers')
Now in ./server.js, add the following
app.post('/create', async (req, res) ⇒ {
//check if req.body is empty
if (!Object.keys(req.body).length) {
res.status(400).json({
message: ‘Request body cannot be empty’
})
}
const {title, author, publisher, read} = (req.body)
// create a record in db
const book = await create({title, author, publisher, read})
if (book.error) {
res.status(500).json({
message: book.error
})
}
res.status(201).json({
message: ‘New book record created’
})
})
READ
Read all
To read all book records in the database, create a query that matches all the documents.
In ./dbHelpers.js, add the following
exports.readAll = async () ⇒ {
try{
const books = await Book.find({})
if (!books) throw New Error()
return {error: null, data: books}
}catch(error) {
return {error: error.message, data: null)
}
}
Add route in ./server.js
. . .
const {create, readAll } = require('./dbHelpers')
. . .
app.get('/read-all', async (req, res) ⇒ {
const books = await readAll()
if (books.error) {
res.status(500).json({
message: error.message,
books: books.data
})
}
res.status(200).json({
message: ‘success’,
books: books.data
})
})
Read One
To retrieve one record, use,findById and pass the Id in the URL as a parameter.
Add a helper function in ./dbHelpers.js
exports.readOne = async (id) ⇒ {
try{
const book = await Book.findByIdAndUpdate(id)
if(!book) throw new Error()
return {error: null, data:book}
} catch (error) {
return {error: error.message, data:null}
}
}
Add route in ./server.js
. . .
const {create, readAll, readOne } = require('./dbHelpers')
. . .
app.get('/read-one/:bookID', async (req, res) ⇒ {
const book = await readOne(req.params.bookID)
if (book.error) {
res.status(500).json({
message: book.error,
books: book.data
})
}
res.status(200).json({
message: 'success',
book: book.data
})
})
UPDATE
Pass in the id of the document you want to update via the URL and the data to update via the request body.
In ./dbHelpers.js
exports.update = async (id, data) ⇒ {
try{
const updatedBook = await Book.findByIdAndUpdate(id, data,{new: true})
if(!updatedBook) throw new Error()
return {error: null, data: updatedBook}
} catch (error) {
return {error: error.message, data: null}
}
}
In ./server.js
. . .
const {create, readAll, readOne, update } = require('./dbHelpers')
. . .
app.put('/update/:bookID', async (req, res) ⇒ {
if (!Object.keys(req.body).length) {
res.status(400).json({
message: ‘Request body cannot be empty’,
book: null
})
}
const book = await update(req.params.bookID, req.body)
if (book.error) {
res.status(500).json({
message: book.error,
book: book.data
})
}
res.status(200).json({
message: ‘success’,
book: book.data
})
})
DELETE
Delete One
Pass the Id of the document to delete via the URL.
In ./dbHelpers.js
exports.deleteOne = async (id) ⇒ {
try{
const isDeleted = await Book.findByIdAndDelete(id)
if (!isDeleted) throw new Error('')
return { error: null}
}catch (error) {
return { error: error.message}
}
}
In ./server.js
. . .
const {create, readAll, readOne, update, deleteOne } = require('./dbHelpers')
. . .
app.delete('/delete/:bookID', async (req, res) ⇒ {
const isDeleted = await deleteOne(req.params.bookID)
if (isDeleted.error) {
res.status(500).json({
message: isDeleted.error,
})
}
res.status(200).json({
message: 'Deleted Successfully)
})
})
Delete All
In ./dbHelpers.js
exports.deleteAll = async () ⇒ {
try{
const isDeleted = await Book.deleteMany({})
if (!isDeleted) throw new Error('')
return {error: null}
}catch (error) {
return { error: error.message }
}
}
In ./server.js
. . .
const {create, readAll, readOne, update, deleteOne, deleteAll } = require('./dbHelpers')
. . .
app.delete('/delete-all', async (req, res) ⇒ {
const isDeleted = await deleteAll(req)
if (isDeleted.error) {
res.status(500).json({
message: isDeleted.error,
})
}
res.status(200).json({
message: 'Deleted Successfully)
})
})
And that's it a simple CRUD API using mongoose, express, and nodeJS.
I learned a lot when writing this post and I hope you learn something too.
If there is anything in this post that is not clear please let me know in the comments.
Thanks for reading and Happy coding ☺️
Upvote
Remi Gathoni
Software developer. Technical Writer . NodeJS/MongoDB/ReactJS

Related Articles