Table of Contents
- What is NestJS?
- Why use NestJS?
- What is Joi?
- Building a basic API with NestJS
- The importance of object validation
- Implementing Joi in NestJS
When building a robust and scalable API, it’s important to implement proper validation within your application not only in terms of security but also to keep your database clean. If you’re working with robust backend APIs, NestJS can be a great tool to use, and, you can add object validation with NestJS and Joi to make your application secure.
This article will show you how to implement Joi object validation in NestJS via a basic CRUD example.
What is NestJS?
Heavily inspired by Angular, NestJS is an especially popular framework for building scalable and robust applications. It provides a clean architecture based on modules, controllers, and providers to help you get started. It supports TypeScript, but you can also write your applications with vanilla JavaScript.
NestJS doesn’t impose any programming paradigm on you. You are free to use object-oriented, functional, or functional reactive programming. It also provides an excellent routing mechanism under the hood and natively supports the HTTP server framework Express. You can also configure your NestJS application to use Fastify.
The building blocks of NestJS
NestJS has three main building blocks: modules, controllers, and providers.
- Modules: modules are used to modularize the codebase and split it into reusable components. TypeScript files that are grouped are described with the
@Module
decorator to provide metadata. NestJS uses these files to organize the application structure - Controllers: controllers control the incoming requests and send the appropriate response to the client
- Providers: providers are the fundamental concept of NestJS. Services, factories, helpers, repositories, etc., are treated as providers in Nest. Providers can be injected as a dependency in Nest
Why use NestJS?
In recent years, Node.js has become a popular programming language, and, because developers want to write production-ready APIs faster, the demand for a quality backend framework has also increased. Enter NestJS, which helps developers write efficient codes faster.
Let’s discuss the benefits of using NestJS.
- TypeScript: NestJS uses TypeScript by default, but you can also write your NestJS code with vanilla JavaScript
- Microservices: NestJS supports GraphQL, WebSockets, gRPC, and MQTT, along with REST APIs. The support for these tools helps to write microservices
- CLI: Nest also has its own CLI, which enables you to create, run, build your applications, and more
- High-quality documentation: NestJS is well documented and helps you to understand the concepts in depth. It even offers official courses created by NestJS team members
- Testing: NestJS provides support for testing your application with Jest, or any other testing framework of your choice. NestJS even provides a testing package of its own
What is Joi?
All developers know that it’s vital to validate data coming from clients. If you have ever used MongoDB and mongoose in Node.js, you are likely familiar with mongoose schemas. Mongoose schemas help describe the data and easily add validators for the data. Joi is very similar to schemas.
Joi is a widely used Node.js data validation library that provides a simple, intuitive, and readable API to describe data. It’s primarily used to validate data sent from API endpoints and allows you to create blueprints of the data type you want to accept.
Here is a simple example of describing schema with Joi:
const schema = Joi.object().keys({ name: Joi.string().alphanum().min(3).max(30).required(), birthyear: Joi.number().integer().min(1970).max(2013), });
Building a basic API with NestJS
NestJS provides many options to scaffold code according to your needs, such as the CRUD recipe. This allows you to scaffold a CRUD with endpoints within a few seconds from the Nest CLI.
To install the Nest CLI on your computer, run the following command:
npm i -g @nestjs/cli
The next step is to generate a Nest application. The Nest CLI uses the following command:
nest new project-name
Here, project-name
is the name of the project. After the command completes, run the following command to scaffold the CRUD endpoints:
nest g resource users
It’ll ask you a few questions, such as which transport layer to use. Once you choose the options according to your preference, Nest will scaffold the CRUD API. For example, an API with the users
endpoint will be generated from the above command. You can see the new users
folder.
Now, if you run the application with npm run start:dev
, you’ll see the endpoints logged in the console. Your server will be started at port 3000
.
You can either check the endpoints by visiting them or opening the users.controllers.ts
file. This file contains the routes for the CRUD API. The services for each API are defined in the users.service.ts
file, and all these files are under the users
folder.
The importance of object validation
If you look at the GET
method for finding a single item in the users.controllers.ts
file, you’ll find that there is no validation set up. You can use anything as an ID, and Nest will not throw a validation error.
The OWASP top ten list of security risks mentions that injection attack is still one of the most popular security risks. OWASP also mentions that an application is vulnerable to injection attacks when “user-supplied data is not validated, filtered, or sanitized by the application.”
This clearly shows that data validation is an important security concern to keep in mind when building applications. There are built-in pipes that can verify or modify the input. NestJS has eight built-in pipes. If you want the ID to be only of integer type, you can use the ParseIntPipe
pipe. Here’s an example:
@Get(':id') findOne(@Param('id', ParseIntPipe) id: string) { return this.usersService.findOne(+id); }
If you try to hit the endpoint with any ID other than a numeric value, you’ll receive the following error.
Using a built-in pipe is simple, but using it for a large schema is complicated. Joi makes it easier to design schemas and implement validation in NestJS. Let’s implement Joi for the NestJS project.
Implementing Joi in NestJS
Generally, any script that can be injected into NestJS is the Pipe
class. Pipes primarily have two use cases:
- Transforming input data
- Validating input data
You can read more about pipes in the official documentation.
The first step is to install the necessary packages. Here, only the Joi package is required. Run the following command to install the package.
npm i joi
Now, create a new file called validation.pipe.ts
inside the users
directory. Creating a custom pipe to implement validation is pretty straightforward. Here’s a code snippet to help you understand.
import { PipeTransform, BadRequestException, ArgumentMetadata } from '@nestjs/common'; export class ValidationPipe implements PipeTransform { transform(value: any, metadata: ArgumentMetadata) { return value; } }
Any schema passed into this pipe constructor will be checked for the configured Joi validation schema. To make the above validator work, open the create-user.dto.ts
file inside the dto
folder.
Here, define a schema type that the API will use when saving the data. For simplicity, assume that the schema sent by the user and held by the database have the same structure.
Let’s assume the API takes firstname
, lastname
, email
, isVerified
, and phoneNumber
as input. The DTO will look like this:
export class CreateUserDto { public firstname: string; public lastname: string; public isVerified: boolean; public email: string; public phoneNumber: number; }
Now, define the Joi schema inside the user.dto.js
file. You can also use separate files to store the schemas. The Joi user schema is simple for this example.
import Joi from 'joi'; export const UserSchema = Joi.object({ firstname: Joi.string().required(), lastname: Joi.string().required(), email: Joi.string().email().required(), isVerified: Joi.boolean().required(), phoneNumber: Joi.number(), }).options({ abortEarly: false, });
The schema is pretty self-explanatory. The string()
method ensures that the input is of type string
, and the required()
method makes certain the fields are inside the input. Similarly, boolean
and number
make sure the types are boolean or number.
The options
method takes other options inside an object. The abortEarly
method, when set to true
, stops the validation when it finds the first error. Otherwise, it returns all the errors.
Now that the schemas are ready, it is time to update the validation pipe accordingly.
Here is the complete validation.pipe.ts
file.
import { PipeTransform, BadRequestException } from '@nestjs/common'; import { CreateUserDto } from './dto/create-user.dto'; import { UserSchema } from './dto/user.dto'; export class CreateUserValidatorPipe implements PipeTransform<CreateUserDto> { public transform(value: CreateUserDto): CreateUserDto { const result = UserSchema.validate(value); if (result.error) { const errorMessages = result.error.details.map((d) => d.message).join(); throw new BadRequestException(errorMessages); } return value; } }
The custom validator class accepts and returns the CreateUserDto
class. The const result = UserSchema.validate(value);
validates the result according to the defined Joi schema. If the result has any errors, the results are mapped using the map
method. The error messages are joined together. Finally, the error messages are sent to the client. Otherwise, it returns the input value.
If the input passes the validation, it’ll show the message, “This action adds a new user
,” according to the method defined inside the user.service.ts
file.
We’ve now implemented Joi into NestJS. You can see if the validation is working by sending the JSON payload to the endpoint http://localhost:3000/users
.
The above image shows what it looks like when the payload passes the validation. Similarly, the image below shows different errors based on the validation.
Conclusion
This article provided an overview of NestJS and Joi and the importance of validation in our apps, then walked you through implementing validation within a NestJS application. I hope you found it useful.
Remember: it is essential to implement proper validation methods to build a robust application. You can check out the Joi and NestJS documentation to better understand the library and frameworks.
The post Understanding object validation with Joi in NestJS appeared first on LogRocket Blog.
from LogRocket Blog https://ift.tt/YJFZnLf
via Read more