## Introduction to Middleware

Welcome to this lesson on configuring middleware and data validation in _NestJS_. So far, we have covered the basics of integrating _MongoDB_ into your NestJS application and transforming data store objects into Data Transfer Objects (`DTOs`). These foundational steps have prepared you for building a functional ToDo app. Today, we'll take another important step by learning how to create and configure middlewares and add data validation in NestJS.

Middlewares play a crucial role in enterprise applications, providing functionalities like logging, authentication, and error handling. By the end of this lesson, you'll know how to create and integrate a timer middleware to monitor the performance of your application.

Validation, on the other hand, ensures that the data sent to your application meets predefined criteria. This is crucial for maintaining data integrity and security. By validating data, you can prevent common vulnerabilities, such as SQL injection and XSS attacks, and ensure that your application behaves as expected regardless of the input it receives.

## Creating a Timer Middleware

A Middleware is a function that has access to the request and response objects and can modify them or end the request/response cycle. Let's create a timer middleware to log the duration of each request.

### Step-by-Step Guide

`app/src/middlewares/timer.middleware.ts`

```typescript
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

@Injectable()
export class TimerMiddleware implements NestMiddleware {
    use(req: Request, res: Response, next: NextFunction) {
        // Get the time we receive the request
        const start = Date.now();

res.on('finish', () => {
            // When the response finishes, determine how long it took to process the request and log it
            const duration = Date.now() - start;
            console.log(`${req.method} ${req.originalUrl} [${res.statusCode}] - ${duration}ms`);
        });
        next();
    }
}
```

### Explanation of the Code

- **Imports**: We import necessary classes and types from `@nestjs/common` and `express`.
- `@Injectable()`: Marks the class as a provider that can be injected into other parts of the application.
- **NestMiddleware Interface**: Ensures the class adheres to the middleware structure in _NestJS_. 
- **use Method**: Contains the logic to start a timer when the request is received and log the duration once the response is finished.

### Understanding "use"

The `use` method above is the core of the middleware function. It intercepts requests made to the server, allowing us to process or log information before the request moves to the next middleware or the route handler.

- **req**: Represents the incoming HTTP Request object. It contains information such as headers, the HTTP method (GET, POST, etc.), and the requested URL.
- **res**: Represents the Response object. It is used to send a response back to the client after processing the request.
- **next**: A callback function that tells NestJS to pass control to the next middleware or route handler. Without calling `next()`, the request would hang, as the server would not know that processing should continue.

## Integrating Middleware in the NestJS Application

Next, we need to register and integrate the timer middleware into our application.

### Step-by-Step Guide

`app/src/app.module.ts`

```typescript
import { Module, MiddlewareConsumer, NestModule } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { TodoModule } from './todo/todo.module';
import { TimerMiddleware } from './middlewares/timer.middleware';

@Module({
    imports: [
        MongooseModule.forRoot('mongodb://localhost/nestjs-todo'),
        TodoModule,
    ],
})
export class AppModule implements NestModule {
    configure(consumer: MiddlewareConsumer) {
        consumer
            .apply(TimerMiddleware)
            .forRoutes('*');
    }
}
```

### Explanation of the Code

- **Imports**: We import required modules like `MiddlewareConsumer` and `NestModule` from `@nestjs/common`.
- **apply Method**: Registers the `TimerMiddleware`.
- **forRoutes('*')**: Applies the middleware to all routes in the application.

## Verification

Run the script and check the console logs to see the timer middleware outputs, e.g.,

```
POST /todos [201] - 15ms
POST /todos [400] - 10ms
GET /todos [200] - 5ms
```

## Adding Validation to CreateTodoDto

In addition to middleware, validation is a key aspect of building reliable and secure enterprise applications. Let's add validation to the `CreateTodoDto` to ensure that the data sent to your application meets certain criteria.

### Step-by-Step Guide to Adding Validation

Install Class-Validator package

```sh
npm install class-validator
```

These libraries provide decorators and tools to validate and transform objects, which integrate seamlessly with NestJS. We'll install this for you.

### Add Validation Decorators to `CreateTodoDto`:

`app/src/dtos/todo.dto.ts`

```typescript
import { IsNotEmpty, IsString, IsOptional } from 'class-validator';

export class CreateTodoDto {
    @IsNotEmpty()
    @IsString()
    title: string;

@IsOptional()
    @IsString()
    description?: string;
}
```

### Explanation of the Code

- **Imports**: We import required decorators from `class-validator`.
- **@IsNotEmpty()**: Ensures the field is not empty.
- **@IsString()**: Ensures the field is a string.
- **@IsOptional()**: Marks the field as optional.

## Use the ValidationPipe

`app/src/todo/todo.controller.ts`

```typescript
@Post()
async create(@Body(new ValidationPipe()) todo: CreateTodoDto): Promise<TodoDto> {
    const newTodo = await this.todosService.createTodo(todo);
    return transformTodoDto(newTodo);
}
```

### Explanation of the Code

- **ValidationPipe**: A built-in pipe provided by _NestJS_ that can be used to validate the request data based on the rules defined in the `DTO`.
- **@Body(new ValidationPipe())**: This decorator applies the `ValidationPipe` to the `todo` parameter, ensuring that the data conforms to the structure and validation rules specified in the `CreateTodoDto` class before it proceeds to the `create` method.
- **CreateTodoDto**: This is the `DTO` that contains validation decorators like `@IsString()`, `@IsNotEmpty()`, etc., to enforce the required data format and constraints.

By using the `ValidationPipe`, the controller method `create` ensures that the `todo` object is valid, adhering strictly to the defined schema in `CreateTodoDto`. If the validation fails, an error response is sent back to the client automatically, stopping the method execution. This helps maintain data integrity and prevents potential issues arising from malformed data.

## Summary and Next Steps

In this lesson, we explored middleware and data validation in _NestJS_. We focused on creating and configuring a timer middleware as well as adding validation to our DTOs.

- **Recap**: Middlewares and Validation are crucial for intercepting and handling requests/responses, and validation ensures data integrity and security. We created a timer middleware to log request durations and added validation to our `CreateTodoDto` to ensure data meets the required criteria.
- **Practice**: Now that you have learned these concepts, you will get hands-on practice with exercises provided after this lesson. This will solidify your understanding of configuring middleware and adding validation in _NestJS_.
- **What's Next**: In the upcoming lessons, we will delve deeper into other advanced topics such as advanced error handling, authentication, and authorization, which are essential for building robust enterprise applications.

Congratulations on making it this far. Let's move on to the exercises to reinforce your learning!
