To create a NestJS application, you'll need the Nest CLI. Install it globally using npm:
$ npm install -g @nestjs/cli
Use the Nest CLI to generate a new NestJS project. Replace bike-store-app with your preferred project name and select your preferred package installer:
nest new bike-store-app
NestJS projects follow a specific directory structure. You'll find directories like src for your source code, main.ts as the entry point, and app.module.ts as the root module.
For this exercise, we will remove the app.controller.ts, app.spec.ts and app.service.ts
.
After deleting the corresponding files, is necessary to fix the import call in the app.module.ts
In NestJS, resources typically refer to various components and modules that you use to build your application. These resources include controllers, services, modules, and other parts of your NestJS application.
let's create our bike resource:
nest g resource bikes --no-spec
For this step, we're going to define the properties for the entity created in the resource
In my case:
export class Bike {
id: string;
brand: string;
model: string;
price: number;
}
And for the purpose of using ids as a unique identifier, we are going to use the uuid library.
$ npm i uuid
At this stage, we'll define our DTOs adding some @decorators to extend the class-validator library.
$ npm i --save class-validator class-transformer
Selecting create-bike.dto.ts
:
import { IsNumber, IsString, Min } from 'class-validator';
export class CreateBikeDto {
@IsString()
brand: string;
@IsString()
model: string;
@IsNumber()
@Min(0)
price: number;
}
Selecting update-bike.dto.ts
:
import { IsNumber, IsString, Min } from 'class-validator';
export class UpdateBikeDto {
@IsString()
brand: string;
@IsString()
model: string;
@IsNumber()
@Min(0)
price: number;
}
In this step, it is necessary to inject the bikes.service.ts
service into the controller. NestJS utilizes dependency injection to handle the connections between the components within the application.
For this we'll be aware of the bikes.module.ts
is using as a provider the bikes.service.ts
If your application requires database interaction, you can use libraries like TypeORM or Sequelize to connect to your database. However, for this example we are going to use a local collection for handle the data.
import { Bike } from './entities/bike.entity';
import { v4 as uuid } from 'uuid';
@Injectable()
export class BikesService {
private bikes: Bike[] = [
{
id: uuid(),
brand: 'Suzuki',
model: 'Gsxs750',
price: 14000,
},
{
id: uuid(),
brand: 'Yamaha',
model: 'MT-07',
price: 12000,
},
{
id: uuid(),
brand: 'Kawasaki',
model: 'Z900',
price: 15000,
},
];
.
.
.
.
}
- create
create(createBikeDto: CreateBikeDto) {
const newBike = {
id: uuid(),
...createBikeDto,
};
this.bikes.push(newBike);
return newBike;
}
- findAll
findAll() {
return this.bikes;
}
- findOne
findOne(id: string) {
const bike = this.bikes.find((bike) => bike.id === id);
if (!bike) {
throw new Error(`Bike with id ${id} not found`);
}
return bike;
}
- update
update(id: string, updateBikeDto: UpdateBikeDto) {
if (!updateBikeDto) {
throw new Error('Bike format is not correct');
}
let bike = this.findOne(id);
this.bikes = this.bikes.map((b) => {
if (b.id === id) {
bike = {
...bike,
...updateBikeDto,
};
return bike;
}
return b;
});
return bike;
}
- remove
remove(id: string) {
const bike = this.findOne(id);
this.bikes = this.bikes.filter((bike) => bike.id !== id);
return bike;
}
In the controller, you can use decorators such as @Get(), @Post(), etc., to specify routes and link them to controller methods. Here, we'll inject the functions previously defined in the bikes.service.ts
.
- @Post()
create(@Body() createBikeDto: CreateBikeDto) {
return this.bikesService.create(createBikeDto);
}
- @Get()
findAll() {
return this.bikesService.findAll();
}
- @Get(':id')
findOne(@Param('id', ParseUUIDPipe) id: string) {
return this.bikesService.findOne(id);
}
- @Patch(':id')
update(
@Param('id', ParseUUIDPipe) id: string,
@Body() updateBikeDto: UpdateBikeDto,
) {
return this.bikesService.update(id, updateBikeDto);
}
- @Delete(':id')
remove(@Param('id', ParseUUIDPipe) id: string) {
return this.bikesService.remove(id);
}
In NestJS, the useGlobalPipes() method is used to configure global pipes for request data transformation and validation. Pipes in NestJS are responsible for processing incoming request data, such as parameters, query strings, request bodies, and headers, before it reaches the route handler method.
Using useGlobalPipes() is a way to apply a specific set of pipes globally to all routes or to specific contexts within your application. Here's how we can use useGlobalPipes() in the main.ts
file.
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Configure a global validation pipe
app.useGlobalPipes(
new ValidationPipe({
transform: false, // Automatically transforms input data to the DTO class
whitelist: true, // Strips any properties that are not defined in the DTO class
forbidNonWhitelisted: true, // Throws an error if non-whitelisted properties are present
}),
);
await app.listen(3000);
}
After completing the previous steps, we should finally have our bikes API up and running. It has been created from scratch and is now ready to be tested in our client API.
To start your NestJS application, run:
$ npm run start
- Aldair Bernal - Full work - Aldair47x
Follow me! – aldair47x@Twitter – [email protected]
This project is licensed under the MIT License - see the LICENSE.md file for details