Logging the User In - Implementation
1 - Route Name
Let's add the route and the controller in first.
POST /api/v1/auth/login
File: src/routes/index.js
const express = require('express')
const router = express.Router()
const userRoutes = require('./user.route')
const authRoutes = require('./auth.route')
function getRouter() {
router.use('/users', userRoutes)
router.use('/auth', authRoutes) // our new route
return router
}
module.exports = getRouterFile: src/routes/auth.route.js
const express = require('express')
const router = express.Router()
const { logUserIn } = require('../controllers/auth')
router.post('/login', logUserIn)
module.exports = routerFile: src/controllers/auth/logUserIn.js
const catchExceptions = require('../utils/catchExceptions')
const logUserIn = catchExceptions(async (req, res, next) => {
// Code goes here...
})2 - Input Request
Next we'll add in the DTO, let's call it loginUserRequestDto.
const ApiException = require('../utils/ApiException')
const fields = ['email', 'password']
const loginUserRequestDto = (data) => {
const errors = []
fields.forEach((field) => {
if (!(field in data)) {
errors.push(`This DTO's property is required: ${field}.`)
}
})
if (errors.length > 0) {
throw new ApiException({
status: 'error',
code: 422,
message: 'loginUserRequestDto failed.',
data: null,
errors
})
}
return data
}
module.exports = loginUserRequestDto3 - Middleware
None.
4 - Validation
Now time for the validator.
const Validator = require('validatorjs')
const ApiException = require('../utils/ApiException')
/**
* @param {*} data {
* - email
* - password
* }
*
* @returns Validator
*/
const loginUserValidator = (data) => {
const rules = {
email: 'required|email',
password: 'required'
}
const validator = new Validator(data, rules)
if (validator.fails()) {
let errors = []
for (const field in validator.errors.errors) {
errors = errors.concat(validator.errors.errors[field])
}
throw new ApiException({
message: 'There were errors with the validation',
status: 'error',
code: 400,
data: null,
errors: validator.errors.errors
})
}
return validator
}
module.exports = loginUserValidator5 - Domain
For checking if there is a match in our database, we'll use our userModel that was created in the last section.
We'll add a new method called findUserByEmailAndPassword which will simply use our userModel to do a find in our database.
File: src/domain/services/userRepository.js
const UserModel = require('../models/user.model')
/**
*
* @param {*} user {
* - name
* - email
* - password
* }
*
* @returns user
*/
const findUserByEmailAndPassword = async (userData) => {
const foundUser = await UserModel.findOne(userData)
return foundUser
}Once we have database query done, we'll add a new method called loginUser and use it in our authService. Notice here that we throw and exception if we do not find any users in the database. This would mean that the client's request has failed.
File: src/domain/services/authService.js
/**
* @returns user
*/
const loginUser = async (user) => {
const loginUser = await userRepository.findUserByEmailAndPassword(user)
if (!loginUser) {
throw new ApiException({
status: 'error',
code: 400,
message: `Invalid credentials, please try a different email and password combination.`,
data: null,
errors: [
`Invalid credentials, please try a different email and password combination.`
]
})
}
return loginUser
}6 - Events
None.
7 - Response
Now to put everything all together. We'll reuse our userResponseDto from last section and log the user into our session with a simple req.session.user.
Once again, our code looks nice and clean 😎.
/**
* Logs the user in and set a session for it.
*/
const logUserIn = catchExceptions(async (req, res) => {
const loginUserRequest = loginUserRequestDto(req.body)
loginUserValidator(loginUserRequest)
// if the user's email and password match in our database
// then set the current session to that user
const loggedInUser = await authService.loginUser(loginUserRequest)
// If there we find a user with authService.loginUser, then
// we'll set the current session to that user
req.session.user = loggedInUser
const userDto = userResponseDto(loggedInUser)
res.status(200).json(
globalResponseDto({
status: 'success',
code: 200,
message: `The user has successfully logged in.`,
data: userDto,
errors: null
})
)
})
module.exports = logUserInLast updated