π Building Toy: REST API in NestJS
Aakash Apoorv
Posted on June 1, 2024
Hey everyone! π
π€ Ever wondered how to start building backend applications? Let's dive into creating your first to-do app with NestJS and Node.js!
Whether you're new to backend development or just brushing up on your skills, this guide is perfect for you. We'll start with a basic To-Do application and even integrate Swagger for live API documentation. π
π§ What Youβll Learn:
- Set up a basic To-Do application using NestJS.
- Integrate Swagger to create interactive API documentation.
- Understand the basics of Node.js and NestJS frameworks.
π‘ Why Build a Toy To-Do App?
Itβs a fantastic exercise for beginners aiming to learn about backend development. Plus, the integration of Swagger enhances your app with interactive API documentation that can be tested directly from your browser.
Getting Started
Installing Node.js v20.9.0
Ensure you have the latest LTS version of Node.js installed using nvm:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
nvm install 20.9.0
nvm use 20.9.0
Setting Up the NestJS Project
Install the NestJS CLI:
npm i -g @nestjs/cli
nest new todo-app
cd todo-app
Create a To-Do Module:
nest generate module todos
nest generate service todos
nest generate controller todos
These commands set up the basic structure for managing To-Do items.
Building the Application
Step 1: Define the To-Do Model
Create a todo.model.ts
in the src/todos
folder:
export class Todo {
id: string;
title: string;
description?: string;
isCompleted: boolean;
}
Step 2: Create a DTO
Define the structure for creating new To-Do items with create-todo.dto.ts
:
export class CreateTodoDto {
title: string;
description?: string;
}
Step 3: Implement the Service
Install UUID:
npm install uuid
Services in NestJS handle business logic. Hereβs how you set up todos.service.ts
:
import { Injectable } from '@nestjs/common';
import { Todo } from './todo.model';
import { CreateTodoDto } from './create-todo.dto';
import { v4 as uuidv4 } from 'uuid';
@Injectable()
export class TodosService {
private todos: Todo[] = [];
findAll(): Todo[] {
return this.todos;
}
findOne(id: string): Todo {
return this.todos.find(todo => todo.id === id);
}
create(createTodoDto: CreateTodoDto): Todo {
const todo: Todo = {
id: uuidv4(),
isCompleted: false,
...createTodoDto
};
this.todos.push(todo);
return todo;
}
update(id: string, updateTodoDto: CreateTodoDto): Todo {
const todo = this.findOne(id);
if (!todo) {
return null;
}
this.todos = this.todos.map(t => t.id === id ? { ...t, ...updateTodoDto } : t);
return this.findOne(id);
}
delete(id: string): boolean {
const initialLength = this.todos.length;
this.todos = this.todos.filter(todo => todo.id !== id);
return this.todos.length < initiallyLength;
}
}
Step 4: Implement the Controller
Controllers manage incoming HTTP requests:
import { Controller, Get, Post, Put, Delete, Body, Param } from '@nestjs/common';
import { TodosService } from './todos.service';
import { Todo } from './todo.model';
import { CreateTodoDto } from './create-todo.dto';
@Controller('todos')
export class TodosController {
constructor(private readonly todosService: TodosService) {}
@Get()
findAll(): Todo[] {
return this.todosService.findAll();
}
@Post()
create(@Body() createTodoDto: CreateTodoDto): Todo {
return this.todosService.create(createTodoDto);
}
}
Adding Swagger Documentation
Swagger integration in NestJS is straightforward thanks to the @nestjs/swagger
module:
Install Swagger Module:
npm install @nestjs/swagger swagger-ui-express
Setup Swagger in your main application file (main.ts
):
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { AppModule } from './app.module';
import { NestFactory } from '@nestjs/core';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const config = new DocumentBuilder()
.setTitle('To-Do API')
.setDescription('The To-Do API description')
.setVersion('1.0')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);
await app.listen(3000);
}
bootstrap();
Running the Application
npm run start:dev
Visit http://localhost:3000/api
to see your interactive Swagger API documentation, where you can also test your API endpoints.
Adding Swagger annotations
Step 5: Add Swagger annotations to To-Do Model
Enhance your data model with Swagger annotations. Modify todo.model.ts
:
import { ApiProperty } from '@nestjs/swagger';
export class Todo {
@ApiProperty({
description: 'Unique identifier of the todo item',
example: 'a1b2c3'
})
id: string;
@ApiProperty({ description: 'Title of the todo item', example: 'Buy milk' })
title: string;
@ApiProperty({
description: 'Detailed description of the todo item',
example: 'Buy low-fat milk from the local store',
required: false
})
description?: string;
@ApiProperty({
description: 'Indicates whether the todo item is completed',
example: false
})
isCompleted: boolean;
}
Step 6: Add Swagger annotations to DTO
The CreateTodoDto
also benefits from Swagger annotations, Modify create-todo.dto.ts
:
import { ApiProperty } from '@nestjs/swagger';
export class CreateTodoDto {
@ApiProperty({ description: 'Title of the todo item', example: 'Buy milk' })
title: string;
@ApiProperty({
description: 'Detailed description of the todo item',
example: 'Buy low-fat milk from the local store',
required: false
})
description?: string;
}
Step 7: Add Swagger annotations to Controller
Controllers todos.controller.ts
now utilize Swagger to document the API routes:
import {
Controller,
Get,
Post,
Put,
Delete,
Body,
Param
} from '@nestjs/common';
import { TodosService } from './todos.service';
import { Todo } from './todo.model';
import { CreateTodoDto } from './create-todo.dto';
import { ApiTags, ApiBody, ApiResponse } from '@nestjs/swagger';
@Controller('todos')
export class TodosController {
constructor(private readonly todosService: TodosService) {}
@Get()
@ApiResponse({ status: 200, description: 'Get all todos', type: [Todo] })
findAll(): Todo[] {
return this.todosService.findAll();
}
@Get(':id')
@ApiResponse({ status: 200, description: 'Get a todo', type: Todo })
findOne(@Param('id') id: string): Todo {
return this.todosService.findOne(id);
}
@Post()
@ApiBody({ type: CreateTodoDto })
@ApiResponse({ status: 201, description: 'Create a new todo', type: Todo })
create(@Body() createTodoDto: CreateTodoDto): Todo {
return this.todosService.create(createTodoDto);
}
@Put(':id')
update(
@Param('id') id: string,
@Body() updateTodoDto: CreateTodoDto
): Todo {
return this.todosService.update(id, updateTodoDto);
}
@Delete(':id')
delete(@Param('id') id: string): boolean {
return this.todosService.delete(id);
}
}
Running the Application Again (If stopped)
npm run start:dev
Visit http://localhost:3000/api
to see your interactive Swagger API documentation with models descriptions.
Happy Coding π
Quick notes on Swagger
Swagger is often mentioned alongside the OpenAPI Specification, but it's important to understand the distinction and connection between them. Swagger, initially a combination of tools for designing and documenting RESTful APIs, has evolved to be closely associated with the OpenAPI Specification.
Category | Description |
---|---|
Swagger Tools | Originally, Swagger included tools like Swagger UI, Swagger Editor, and Swagger Codegen for designing, documenting, and consuming RESTful APIs. |
OpenAPI Specification | Initially known as the Swagger Specification, it's a standard format for describing RESTful APIs, facilitating standardized API interactions. |
Relationship | In 2015, Swagger Specification was donated by SmartBear Software to the OpenAPI Initiative and renamed the OpenAPI Specification, while Swagger tools continued to support it. |
Usage | Today, "Swagger" often refers to the suite of tools supporting the OpenAPI Specification, allowing developers to visualize and interact with APIs without direct access to their implementation. |
π₯ Hit 'Fire' if you enjoyed this!
Posted on June 1, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.