DEV Community

Alex Spinov
Alex Spinov

Posted on

NestJS Has a Free API — Here's How to Build Enterprise-Grade Node.js APIs

NestJS is a progressive Node.js framework for building efficient, scalable server-side applications. It uses TypeScript, decorators, and dependency injection — inspired by Angular.

Getting Started

npm install -g @nestjs/cli
nest new my-api
cd my-api
npm run start:dev
Enter fullscreen mode Exit fullscreen mode

Controller

import { Controller, Get, Post, Body, Param, Query } from "@nestjs/common";
import { PostsService } from "./posts.service";
import { CreatePostDto } from "./dto/create-post.dto";

@Controller("posts")
export class PostsController {
  constructor(private readonly postsService: PostsService) {}

  @Get()
  findAll(@Query("limit") limit = 10) {
    return this.postsService.findAll(limit);
  }

  @Get(":id")
  findOne(@Param("id") id: string) {
    return this.postsService.findOne(id);
  }

  @Post()
  create(@Body() createPostDto: CreatePostDto) {
    return this.postsService.create(createPostDto);
  }
}
Enter fullscreen mode Exit fullscreen mode

Service

import { Injectable, NotFoundException } from "@nestjs/common";

@Injectable()
export class PostsService {
  private posts = [];

  findAll(limit: number) {
    return this.posts.slice(0, limit);
  }

  findOne(id: string) {
    const post = this.posts.find(p => p.id === id);
    if (!post) throw new NotFoundException(`Post ${id} not found`);
    return post;
  }

  create(dto: CreatePostDto) {
    const post = { id: crypto.randomUUID(), ...dto, createdAt: new Date() };
    this.posts.push(post);
    return post;
  }
}
Enter fullscreen mode Exit fullscreen mode

DTO with Validation

import { IsString, IsNotEmpty, IsOptional, MinLength } from "class-validator";

export class CreatePostDto {
  @IsString()
  @IsNotEmpty()
  @MinLength(1)
  title: string;

  @IsString()
  @MinLength(10)
  content: string;

  @IsOptional()
  @IsString({ each: true })
  tags?: string[];
}
Enter fullscreen mode Exit fullscreen mode

Module

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

@Module({
  controllers: [PostsController],
  providers: [PostsService],
  exports: [PostsService]
})
export class PostsModule {}
Enter fullscreen mode Exit fullscreen mode

Guards (Authentication)

import { Injectable, CanActivate, ExecutionContext } from "@nestjs/common";

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    const request = context.switchToHttp().getRequest();
    const token = request.headers.authorization?.replace("Bearer ", "");
    return verifyToken(token);
  }
}

// Usage
@UseGuards(AuthGuard)
@Get("profile")
getProfile(@Req() req) {
  return req.user;
}
Enter fullscreen mode Exit fullscreen mode

Interceptors

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler) {
    const now = Date.now();
    return next.handle().pipe(
      tap(() => console.log(`${context.getHandler().name}: ${Date.now() - now}ms`))
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Need to extract or automate web content at scale? Check out my web scraping tools on Apify — no coding required. Or email me at spinov001@gmail.com for custom solutions.

Top comments (0)