NestJS Controllers And Routes Guide Tutorial With Examples

NestJS Controllers And Routes Guide Tutorial With Examples

Guide Tutorial for creating controllers and routes quickly, we will focus on the code for a quick start to develop your Nest application.

Creating a New NestJS Project

We need Node.js and NPM installed on our machine to install Nest CLI to ease the process.

npm i -g @nestjs/cli

If you want to know the available commands for Nest CLI use nest -h in the terminal

Let’s scaffold our project

nest new my-blog

After selecting the package manager and finishing the installation go to the installation folder and run the application

cd my-blog
npm run start

Go to http://localhost:3000/, you should see “Hello World!” if you want to change the server port. Open src\main.ts and change the app.listen in the bootstrap() function

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000); //change the port form 3000 to 3001
}
bootstrap();

Before we go to the next step we need to remove these files

  • src\app.controller.spec.ts
  • src\app.controller.ts
  • src\app.service.ts

Let’s remove these file form src\app.module.ts

import { Module } from '@nestjs/common';

@Module({
  imports: [],
  controllers: [],
  providers: [],
})
export class AppModule {}

Now we have a clean app, let’s create our first controller

NestJS Controller

Let’s create a controller for a blog module. we will use the NestJS command nest generate controller blog but in a short format

nest g co blog

It creates a new folder src\blog with src\blog\blog.controller.spec.ts and src\blog\blog.controller.ts

Looks good, this is the controller code.

import { Controller } from '@nestjs/common';

@Controller('blog')
export class BlogController {}

This command adds the controller to src\app.module.ts. we should create a module for the blog but for now, we will use it like it is.

import { Module } from '@nestjs/common';
import { BlogController } from './blog/blog.controller';

@Module({
  imports: [],
  controllers: [BlogController],
  providers: [],
})
export class AppModule {}

Let’s create our first route.

NestJS Routes

In NestJs we don’t create the routes separately “We don’t do that here”

We use routes decorators inside controllers, such as @Get(), @Post and @Put before the controller functions. Let’s create a route for getting all the blog posts in our blog controller

import { Controller, Get } from '@nestjs/common';

@Controller('blog')
export class BlogController {
  private posts = [
    {id:1, title:'post one', description:'the body of the post one' },
    {id:2, title:'post two', description:'the body of the post two' },
    {id:3, title:'post three', description:'the body of the post three'},
    ];

  @Get()
  findAll() {
    return this.posts;
  }
    
}

@Controller('blog') : this decorator for defining a controller with an entry point to all the sub-routes. In this example here, the route should be http://localhost:3000/blog and we made the entry point to call findAll() by using the @Get() decorator that we import from @nestjs/common.

Notice that @Get() is exactly like @Get('/').

Route Parameters

Let’s create a function for getting the posts by id in the blog controller, We will use the @Param decorator for getting the parameters as in the following example.

import { Controller, 
Param, Get } from '@nestjs/common';
//
@Get(':id')
findOne(@Param('id') id: string) {
    return this.posts.find(o => o.id === id);
}

Now if you open the browser and go to http://localhost:3000/blog/1 it will show the post with id 1.

What if we want to add multiple parameters to the URL? Let’s create a search URL that takes 2 parameters the first for the column (‘title’ or ‘description’) and the second for the search value.

@Get('search/:column/:search')
search(@Param('search') search: string, @Param('column') column: string) {
    return this.posts.find(o => o[column] === search);
}

Try to visit http://localhost:3000/blog/search/title/post%20two it should return the second post.

Route Query

If you want to add more filters to an URL, Queries are the best options. Let’s add more filters in findAll() such as sorting by id asc for ascending and desc for descending

 @Get()
  findAll(@Query('sort') sort) {
    //return this.posts;
    return {sort: sort};
 }

Let’s test the route by visiting http://localhost:3000/blog?sort=asc

NestJS Request Body

Let’s create another example for adding a new blog post. We will create a function with a post route with a request payload. we will use the @Body decorator for getting the body data.

We need to create a Data Transfer Object schema (DTO),  A DTO is an object that defines how the data will be sent over the network. It’s like making TypeScript interfaces. We will put all the DTO files in the new “dto” folder src\blog\dto. Let’s create the first DTO for creating a new post src\blog\dto\create-post.dto.ts

export class CreatePostDto {
    id: string;
    title: string;
    description: string;
}

Now we are ready to create our function.

import { Controller, Param, Get, Query, Post, Body } from '@nestjs/common';
import { CreatePostDto } from './dto/create-post.dto';
//
@Post('create')
create(@Body() createPostDto: CreatePostDto){
     this.posts.push(createPostDto);
     return this.posts
}

Let’s try to send a post request, I’m using postman, and make sure we send the body as “x-www-form-urlencoded”.

nestJS sending post request from postman

More Request Methods

In the above examples, we got all the basics we need to know about creating routes, and for other request methods such as Put, Delete, and Patch, they will be the same but here is one more example for Put and Delete routes.

Let’s create DTO for updating a post by id

export class UpdatePostDto {
    id: string;
    title: string;
    description: string;
}

Here is the controller

import { Controller, Param, Get, Query, Post, Body, Put, Delete } from '@nestjs/common';
import { UpdatePostDto } from './dto/update-post.dto';
//

@Put(':id')
update(@Param('id') id: string, @Body() updatePostDto: UpdatePostDto) {
  console.log(updatePostDto)
  return `This action updates a #${id} post`;
}

Here is a delete function too

@Delete(':id')
remove(@Param('id') id: string) {
  return `This action delete a #${id} post`;
}

DTO with Route Queries

Instead of defining every single query, we can create a DTO class and use the queries as properties of one object.

export class FilterPostsDto {
    sort: string;
    status: string;
}

import { Controller, Param, Get, Query, Post, Body, Put, Delete } from '@nestjs/common';
//
import { FilterPostsDto } from './dto/filter-posts.dto';

@Get('filter/posts')
filterPosts(@Query() query: FilterPostsDto) {
    return `This filter is for sort with # ${query.sort} and status # ${query.status}  post`;
}

Conclusion

NestJS takes the controllers to a new way of use. That is what I felt when I had to deal with a NestJS project couple of months ago. We will miss the routes file but it’s okay, we have decorators for every request method and DTO for the request body and @Query for queries, and @Param for route parameters.

Here is the controller code

import { Controller, Param, Get, Query, Post, Body, Put, Delete } from '@nestjs/common';
import { CreatePostDto } from './dto/create-post.dto';
import { UpdatePostDto } from './dto/update-post.dto';
import { FilterPostsDto } from './dto/filter-posts.dto';
@Controller('blog')
export class BlogController {
  private posts = [
    {id:"1", title:'post one', description:'the body of the post one' },
    {id:"2", title:'post two', description:'the body of the post two' },
    {id:"3", title:'post three', description:'the body of the post three'},
    ];

  @Get()
  findAll(@Query('sort') sort) {
    //return this.posts;
    return {sort: sort};
  }

  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.posts.find(o => o.id === id);
  }

  @Get('search/:column/:search')
  search(@Param('search') search: string, @Param('column') column: string) {
    return this.posts.find(o => o[column] === search);
  }

  @Post('create')
  create(@Body() createPostDto: CreatePostDto){
    console.log(createPostDto)
     this.posts.push(createPostDto);
     return this.posts
  }

  @Put(':id')
  update(@Param('id') id: string, @Body() updatePostDto: UpdatePostDto) {
    console.log(updatePostDto)
    return `This action updates a #${id} post`;
  }

  @Delete(':id')
  remove(@Param('id') id: string) {
    return `This action delete a #${id} post`;
  }

  @Get('filter/posts')
  filterPosts(@Query() query: FilterPostsDto) {
    return `This filter is for sort with # ${query.sort} and status # ${query.status}  post`;
  }

    
}

That’s all, I hope that was useful for you, thank you.