DEV Community

Cover image for πŸš€ Building Toy: REST API in NestJS
Aakash Apoorv
Aakash Apoorv

Posted on • Edited on

πŸš€ Building Toy: REST API in NestJS

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
Enter fullscreen mode Exit fullscreen mode

Setting Up the NestJS Project

Install the NestJS CLI:

npm i -g @nestjs/cli
nest new todo-app
cd todo-app
Enter fullscreen mode Exit fullscreen mode

Create a To-Do Module:

nest generate module todos
nest generate service todos
nest generate controller todos
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Implement the Service

Install UUID:

npm install uuid
Enter fullscreen mode Exit fullscreen mode

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;
  }
}
Enter fullscreen mode Exit fullscreen mode

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);
  }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

Running the Application

npm run start:dev
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
}

Enter fullscreen mode Exit fullscreen mode

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);
    }
}
Enter fullscreen mode Exit fullscreen mode

Running the Application Again (If stopped)

npm run start:dev
Enter fullscreen mode Exit fullscreen mode

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!

Top comments (0)