🚀 Building Toy: REST API in NestJS

RMAG news

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

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 {
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 a todo.model.ts:

import { ApiProperty } from @nestjs/swagger;

export class Todo {
@ApiProperty({ example: 1, description: Unique identifier of the todo })
id: string;

@ApiProperty({ example: Buy groceries, description: Title of the todo })
title: string;

@ApiProperty({ example: Remember to buy milk and eggs, description: Detailed description of the todo, required: false })
description?: string;

@ApiProperty({ example: false, description: Completion status of the todo })
isCompleted: boolean;
}

Step 6: Add Swagger annotations to DTO

The CreateTodoDto also benefits from Swagger annotations:

import { ApiProperty } from @nestjs/swagger;

export class CreateTodoDto {
@ApiProperty({ example: Buy groceries, description: Title of the todo })
title: string;

@ApiProperty({ example: Remember to buy milk and eggs, description: Detailed description of the todo, required: false })
description?: string;
}

Step 7: Add Swagger annotations to Controller

Controllers 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, ApiOperation, ApiResponse } from @nestjs/swagger;

@ApiTags(todos)
@Controller(todos)
export class TodosController {
constructor(private readonly todosService: TodosService) {}

@Get()
@ApiOperation({ summary: Retrieve all todos })
@ApiResponse({ status: 200, description: List of todo items, type: [Todo] })
findAll(): Todo[] {
return this.todosService.findAll();
}

@Post()
@ApiOperation({ summary: Create a new todo })
@ApiResponse({ status: 201, description: The created todo, type: Todo })
create(@Body() createTodoDto: CreateTodoDto): Todo {
return this.todosService.create(createTodoDto);
}

// Continue with other methods using similar Swagger annotations
}

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!