Mary Gathoni
Posted on November 10, 2021
In this post, we will be building a CRUD API with nodeJS and Express.
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 and Mongoose
npm i express mongoose
Create server.js and open VS Code
touch server.js
code .
In ./server.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 middleware 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`
```javascript
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 model
module.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('Book could not be saved')
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('Book not found')
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('Could not retrieve book')
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('Failed to update book')
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('Failed to delete book')
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('Failed to delete books')
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 :)
Posted on November 10, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.