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.
Lesson 01
Separate NestJS modules, controllers, and providers so routing, application logic, and feature wiring stay reviewable.
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 {}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;
}
}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.
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.