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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://book.restfulnode.com/part-3/chapter-8/4-logging-the-user-in-implementation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
