Working with Node.js Entities and Mongoose Models - II
Chiranjib
Posted on February 19, 2023
Previous: Working with Node.js Entities and Mongoose Models - I
The finish line is very close now, let's do it!
Step 1 - understand that the magic happens 'async'
Node.js is single-threaded and JavaScript is asynchronous by design. If you don't know or understand how it works, then I'd strongly advise that you should familiarize with the concepts of asynchronous processing first. Here's a good explanation of the concepts.
Step 2 - modify our controller to support asynchronous processing
In the file ./controllers/index.js
, we need to make the router functions async, and remember to await before returning the response:
const BaseEntity = require('_entities').getBaseEntity();
const logger = require('_utils/logger');
/**
*
* @param {BaseEntity} entityObject
* @returns {[string, Router]}
*/
function getController(entityObject) {
const router = require('express').Router({ mergeParams: true });
router.post('/', async (req, res, next) => {
try {
const response = await entityObject.create(req.body);
res.json(response);
} catch(e) {
logger.error(e);
res.status(500).send('Oops! Something went wrong!');
}
});
router.get('/', async (req, res, next) => {
try {
const response = await entityObject.read();
res.json(response);
} catch(e) {
logger.error(e);
res.status(500).send('Oops! Something went wrong!');
}
});
router.get('/:entityObjectId', async (req, res, next) => {
try {
const response = await entityObject.read(req.params.entityObjectId);
res.json(response);
} catch(e) {
logger.error(e);
res.status(500).send('Oops! Something went wrong!');
}
});
router.put('/:entityObjectId', async (req, res, next) => {
try {
const response = await entityObject.update(req.params.entityObjectId, req.body);
res.json(response);
} catch(e) {
logger.error(e);
res.status(500).send('Oops! Something went wrong!');
}
});
router.delete('/:entityObjectId', async (req, res, next) => {
try {
const response = await entityObject.delete(req.params.entityObjectId);
res.json(response);
} catch(e) {
logger.error(e);
res.status(500).send('Oops! Something went wrong!');
}
});
return [`/${entityObject.name}`, router];
}
module.exports = {
getController
};
Step 3 - Create entities for Movie and User
./entities/movie/index.js
const BaseEntity = require('_entities/BaseEntity');
module.exports = class MovieEntity extends BaseEntity {
constructor() {
super();
this.name = 'Movie';
this.model = require('_data-access/models/Movie');
}
async create(payload) {
return await this.model.create(payload);
}
async read(id) {
if (id) {
return await this.model.findById(id).lean();
} else {
return await this.model.find().lean();
}
}
async update(id, payload) {
return await this.model.findByIdAndUpdate(id, payload, { new: true });
}
};
./entities/user/index.js
const BaseEntity = require('_entities/BaseEntity');
module.exports = class UserEntity extends BaseEntity {
constructor() {
super();
this.name = 'User';
this.model = require('_data-access/models/User');
}
async create(payload) {
return await this.model.create(payload);
}
async read(id) {
if (id) {
return await this.model.findById(id).lean();
} else {
return await this.model.find().lean();
}
}
async update(id, payload) {
return await this.model.findByIdAndUpdate(id, payload, { new: true });
}
};
Take note, both the entities are not supporting the delete
method, so the expectation is that if someone (could be a hacker) hits the DELETE endpoint, they would see that it is not supported.
Step 4 - generate controllers and expose them for the new entities
In our ./index.js
file, we have to make modifications to the setupApp
function as follows:
....
app.use(...getController(entities.getEntityOne()));
app.use(...getController(entities.getMovieEntity()));
app.use(...getController(entities.getUserEntity()));
app.use('/', (req, res) => {
res.send(`${req.originalUrl} can not be served`);
});
....
And that's it! We have a fully functional persistent Node.js backend.
Next: Working with Node.js Entities and Mongoose Models - III
Posted on February 19, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.