# 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*

```javascript
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 = getRouter
```

*File: src/routes/auth.route.js*

```javascript
const express = require('express')
const router = express.Router()
const { logUserIn } = require('../controllers/auth')

router.post('/login', logUserIn)

module.exports = router
```

*File: src/controllers/auth/logUserIn.js*

```javascript
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`.

```javascript
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 = loginUserRequestDto
```

## 3 - Middleware

None.

## 4 - Validation

Now time for the validator.

```javascript
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 = loginUserValidator
```

## 5 - 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*

```javascript
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*

```javascript
/**
 * @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 :sunglasses:.

```javascript
/**
 * 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 = logUserIn
```
