NestJS

Lesson 01

Module, controller, and provider boundaries

Separate NestJS modules, controllers, and providers so routing, application logic, and feature wiring stay reviewable.

Good Code

reviews.module.ts
import { Body, Controller, Injectable, Module, Post } from "@nestjs/common";

@Controller("reviews")
export class ReviewsController {
  constructor(private readonly reviews: ReviewsService) {}

  // The controller reads HTTP input and delegates application work.
  @Post()
  create(@Body() body: CreateReviewDto) {
    return this.reviews.create(body);
  }
}

@Injectable()
export class ReviewsService {
  create(input: CreateReviewDto) {
    return { id: crypto.randomUUID(), ...input };
  }
}

@Module({
  controllers: [ReviewsController],
  providers: [ReviewsService],
})
export class ReviewsModule {}

Bad Code

reviews.controller.ts
import { Body, Controller, Post } from "@nestjs/common";

@Controller("reviews")
export class ReviewsController {
  @Post()
  async create(@Body() body: any) {
    // The controller owns persistence, ids, and HTTP input in one method.
    const review = { id: Date.now(), ...body };
    await db.collection("reviews").insertOne(review);
    return review;
  }
}

Review Notes

What to review

Good Code

The good version gives the controller one job: accept HTTP input and call the service. The module declares the controller and provider that make the feature available.

Bad Code

The bad version puts database writes and id generation inside the controller. That makes route code harder to test and couples HTTP concerns to persistence decisions.

Takeaways

  • Controllers should translate HTTP requests while providers own application work and modules wire the feature together.