Changing the controllers

Since we now have the tests in place and failing, we can change our user and order controllers to start using MongoDB. First, let's change the user controller. The user controller content is as follows:

import { NextFunction, Request, Response } from 'express'
import * as halson from 'halson'
import { UserModel } from '../schemas/User'
import { formatOutput } from '../utility/orderApiUtility'

export let getUser = (req: Request, res: Response, next: NextFunction) => {
const username = req.params.username

UserModel.findOne({ username: username }, (err, user) => {
if (!user) {
return res.status(404).send()
}

user = user.toJSON()
user._id = user._id.toString()

user = halson(user).addLink('self', `/users/${user._id}`)
return formatOutput(res, user, 200, 'user')
})
}

export let addUser = (req: Request, res: Response, next: NextFunction) => {
const newUser = new UserModel(req.body)

newUser.save((error, user) => {
user = halson(user.toJSON()).addLink('self', `/users/${user._id}`)
return formatOutput(res, user, 201, 'user')
})
}

export let updateUser = (req: Request, res: Response, next: NextFunction) => {
const username = req.params.username

UserModel.findOne({ username: username }, (err, user) => {
if (!user) {
return res.status(404).send()
}

user.username = req.body.username || user.username
user.firstName = req.body.firstName || user.firstName
user.lastName = req.body.lastName || user.lastName
user.email = req.body.email || user.email
user.password = req.body.password || user.password
user.phone = req.body.phone || user.phone
user.userStatus = req.body.userStatus || user.userStatus

user.save(error => {
res.status(204).send()
})
})
}

export let removeUser = (req: Request, res: Response, next: NextFunction) => {
const username = req.params.username

UserModel.findOne({ username: username }, (err, user) => {
if (!user) {
return res.status(404).send()
}

user.remove(error => {
res.status(204).send()
})
})
}

Let's walk through this file:

import { UserModel } from '../schemas/User'
export let getUser = (req: Request, res: Response, next: NextFunction) => {
const username = req.params.username

UserModel.findOne({ username: username }, (err, user) => {
if (!user) {
return res.status(404).send()
}

user = user.toJSON()
user._id = user._id.toString()

user = halson(user).addLink('self', `/users/${user._id}`)
return formatOutput(res, user, 200, 'user')
})
}
export let addUser = (req: Request, res: Response, next: NextFunction) => {
const newUser = new UserModel(req.body)

newUser.save((error, user) => {
user = halson(user.toJSON()).addLink('self', `/users/${user._id}`)
return formatOutput(res, user, 201, 'user')
})
}

export let updateUser = (req: Request, res: Response, next: NextFunction) => {
const username = req.params.username

UserModel.findOne({ username: username }, (err, user) => {
if (!user) {
return res.status(404).send()
}

user.username = req.body.username || user.username
user.firstName = req.body.firstName || user.firstName
user.lastName = req.body.lastName || user.lastName
user.email = req.body.email || user.email
user.password = req.body.password || user.password
user.phone = req.body.phone || user.phone
user.userStatus = req.body.userStatus || user.userStatus

user.save(error => {
res.status(204).send()
})
})
}
export let removeUser = (req: Request, res: Response, next: NextFunction) => {
const username = req.params.username

UserModel.findOne({ username: username }, (err, user) => {
if (!user) {
return res.status(404).send()
}

user.remove(error => {
res.status(204).send()
})
})
}

In general words, the order controller changed almost like the User controller such as the following file:

import { NextFunction, Request, Response } from 'express'
import * as halson from 'halson'
import * as _ from 'lodash'
import { OrderModel } from '../schemas/order'
import { UserModel } from '../schemas/User'
import { formatOutput } from '../utility/orderApiUtility'

export let getOrder = (req: Request, res: Response, next: NextFunction) => {
const id = req.params.id
OrderModel.findById(id, (err, order) => {
if (!order) {
return res.status(404).send()
}
order = halson(order.toJSON()).addLink('self', `/store/orders/${order.id}`)
return formatOutput(res, order, 200, 'order')
})
}

export let getAllOrders = (req: Request, res: Response, next: NextFunction) => {
const limit = Number(req.query.limit) || 0
const offset = Number(req.query.offset) || 0

OrderModel.find({}, null, { skip: offset, limit: limit }).then(orders => {
if (orders) {
orders = orders.map(order => {
return halson(order.toJSON())
.addLink('self', `/store/orders/${order.id}`)
.addLink('user', {
href: `/users/${order.userId}`,
})
})
}
return formatOutput(res, orders, 200, 'order')
})
}

export let addOrder = (req: Request, res: Response, next: NextFunction) => {
const userId = req.body.userId

UserModel.findById(userId, (err, user) => {
if (!user) {
return res.status(404).send()
}

const newOrder = new OrderModel(req.body)

newOrder.save((error, order) => {
order = halson(order.toJSON())
.addLink('self', `/store/orders/${order._id}`)
.addLink('user', {
href: `/users/${order.userId}`,
})

return formatOutput(res, order, 201, 'order')
})
})
}

export let removeOrder = (req: Request, res: Response, next: NextFunction) => {
const id = req.params.id
OrderModel.findById(id, (err, order) => {
if (!order) {
return res.status(404).send()
}
order.remove(error => {
res.status(204).send()
})
})
}

export let getInventory = (req: Request, res: Response, next: NextFunction) => {
const status = req.query.status
OrderModel.find({ status: status }, (err, orders) => {
orders = _.groupBy(orders, 'userId')
return formatOutput(res, orders, 200, 'inventory')
})
}
import { OrderModel } from '../schemas/order'
import { UserModel } from '../schemas/User'
export let getOrder = (req: Request, res: Response, next: NextFunction) => {
const id = req.params.id
OrderModel.findById(id, (err, order) => {
if (!order) {
return res.status(404).send()
}
order = halson(order.toJSON()).addLink('self', `/store/orders/${order.id}`)
return formatOutput(res, order, 200, 'order')
})
}
export let getAllOrders = (req: Request, res: Response, next: NextFunction) => {
const limit = Number(req.query.limit) || 0
const offset = Number(req.query.offset) || 0

OrderModel.find({}, null, { skip: offset, limit: limit }).then(orders => {
if (orders) {
orders = orders.map(order => {
return halson(order.toJSON())
.addLink('self', `/store/orders/${order.id}`)
.addLink('user', {
href: `/users/${order.userId}`,
})
})
}
return formatOutput(res, orders, 200, 'order')
})
}
export let addOrder = (req: Request, res: Response, next: NextFunction) => {
const userId = req.body.userId

UserModel.findById(userId, (err, user) => {
if (!user) {
return res.status(404).send()
}

const newOrder = new OrderModel(req.body)

newOrder.save((error, order) => {
order = halson(order.toJSON())
.addLink('self', `/store/orders/${order._id}`)
.addLink('user', {
href: `/users/${order.userId}`,
})

return formatOutput(res, order, 201, 'order')
})
})
}
export let removeOrder = (req: Request, res: Response, next: NextFunction) => {
const id = req.params.id
OrderModel.findById(id, (err, order) => {
if (!order) {
return res.status(404).send()
}
order.remove(error => {
res.status(204).send()
})
})
}
export let getInventory = (req: Request, res: Response, next: NextFunction) => {
const status = req.query.status
OrderModel.find({ status: status }, (err, orders) => {
orders = _.groupBy(orders, 'userId')
return formatOutput(res, orders, 200, 'inventory')
})
}

Finally, if we run the tests, they should pass:

$ npm run test

You will see the following output:

  baseRoute
should respond with HTTP 200 status (109ms)
should respond with success message

userRoute
should respond with HTTP 404 status because there is no user (79ms)
should create a new user and retrieve it back (84ms)
should return the user created on the step before
should updated the user John
should return the user updated on the step before
should return 404 because the user does not exist
should remove an existent user
should return 404 when it is trying to remove an user because the user does not exist

userRoute
should respond with HTTP 404 status because there is no order
should create a new user for Order tests and retrieve it back
should create a new order and retrieve it back (56ms)
should return the order created on the step before
should return all orders so far
should not return orders because offset is higher than the size of the orders array
should return the inventory for all users
should remove an existing order
should return 404 when it is trying to remove an order because the order does not exist


19 passing (643ms)

The same applies to Stryker:

$ stryker run

The previous command will show the following output:

Stryker report after mongo changes