```typescript
// NestJS Complete Application Template
import {
Controller,
Get,
Post,
Put,
Delete,
Body,
Param,
Query,
UseGuards,
Injectable,
Module,
NestFactory,
} from "@nestjs/common";
import {
ApiTags,
ApiOperation,
ApiResponse,
ApiBearerAuth,
ApiQuery,
ApiParam,
} from "@nestjs/swagger";
import {
IsString,
IsEmail,
IsOptional,
IsEnum,
MinLength,
} from "class-validator";
import { JwtAuthGuard } from "./auth/jwt-auth.guard";
// ============================================
// DTOs (Data Transfer Objects)
// ============================================
export class CreateUserDto {
@IsEmail()
email: string;
@IsString()
@MinLength(2)
name: string;
@IsString()
@MinLength(8)
password: string;
}
export class UpdateUserDto {
@IsOptional()
@IsString()
name?: string;
@IsOptional()
@IsString()
bio?: string;
}
export class CreatePostDto {
@IsString()
@MinLength(1)
title: string;
@IsString()
content: string;
@IsOptional()
@IsEnum(["draft", "published"])
status?: "draft" | "published";
}
export class QueryPostDto {
@IsOptional()
@IsString()
search?: string;
@IsOptional()
@IsEnum(["draft", "published"])
status?: "draft" | "published";
@IsOptional()
limit?: number = 20;
@IsOptional()
offset?: number = 0;
}
// ============================================
// Entities
// ============================================
export interface User {
id: string;
email: string;
name: string;
bio?: string;
createdAt: Date;
updatedAt: Date;
}
export interface Post {
id: string;
title: string;
content: string;
authorId: string;
status: "draft" | "published";
views: number;
createdAt: Date;
publishedAt?: Date;
}
// ============================================
// Services
// ============================================
@Injectable()
export class UsersService {
private users: Map<string, User> = new Map();
private idCounter = 1;
async findAll(): Promise<User[]> {
return Array.from(this.users.values());
}
async findById(id: string): Promise<User | undefined> {
return this.users.get(id);
}
async findByEmail(email: string): Promise<User | undefined> {
return Array.from(this.users.values()).find((u) => u.email === email);
}
async create(dto: CreateUserDto): Promise<User> {
const id = String(this.idCounter++);
const user: User = {
id,
email: dto.email,
name: dto.name,
createdAt: new Date(),
updatedAt: new Date(),
};
this.users.set(id, user);
return user;
}
async update(id: string, dto: UpdateUserDto): Promise<User | undefined> {
const user = this.users.get(id);
if (!user) return undefined;
const updated = { ...user, ...dto, updatedAt: new Date() };
this.users.set(id, updated);
return updated;
}
async delete(id: string): Promise<boolean> {
return this.users.delete(id);
}
}
@Injectable()
export class PostsService {
private posts: Map<string, Post> = new Map();
private idCounter = 1;
async findAll(query: QueryPostDto): Promise<{ data: Post[]; total: number }> {
let posts = Array.from(this.posts.values());
if (query.status) {
posts = posts.filter((p) => p.status === query.status);
}
if (query.search) {
const search = query.search.toLowerCase();
posts = posts.filter(
(p) =>
p.title.toLowerCase().includes(search) ||
p.content.toLowerCase().includes(search),
);
}
const total = posts.length;
const data = posts.slice(query.offset, query.offset! + query.limit!);
return { data, total };
}
async findById(id: string): Promise<Post | undefined> {
return this.posts.get(id);
}
async create(dto: CreatePostDto, authorId: string): Promise<Post> {
const id = String(this.idCounter++);
const post: Post = {
id,
title: dto.title,
content: dto.content,
authorId,
status: dto.status || "draft",
views: 0,
createdAt: new Date(),
};
this.posts.set(id, post);
return post;
}
async publish(id: string): Promise<Post | undefined> {
const post = this.posts.get(id);
if (!post) return undefined;
post.status = "published";
post.publishedAt = new Date();
return post;
}
async incrementViews(id: string): Promise<number> {
const post = this.posts.get(id);
if (!post) return 0;
post.views++;
return post.views;
}
async delete(id: string): Promise<boolean> {
return this.posts.delete(id);
}
}
// ============================================
// Controllers
// ============================================
@ApiTags("users")
@Controller("users")
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
@ApiOperation({ summary: "Get all users" })
@ApiResponse({ status: 200, description: "List of users" })
async findAll(): Promise<User[]> {
return this.usersService.findAll();
}
@Get(":id")
@ApiOperation({ summary: "Get user by ID" })
@ApiParam({ name: "id", description: "User ID" })
@ApiResponse({ status: 200, description: "User found" })
@ApiResponse({ status: 404, description: "User not found" })
async findOne(@Param("id") id: string): Promise<User | undefined> {
return this.usersService.findById(id);
}
@Post()
@ApiOperation({ summary: "Create a new user" })
@ApiResponse({ status: 201, description: "User created" })
async create(@Body() dto: CreateUserDto): Promise<User> {
return this.usersService.create(dto);
}
@Put(":id")
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
@ApiOperation({ summary: "Update user" })
async update(
@Param("id") id: string,
@Body() dto: UpdateUserDto,
): Promise<User | undefined> {
return this.usersService.update(id, dto);
}
@Delete(":id")
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
@ApiOperation({ summary: "Delete user" })
async delete(@Param("id") id: string): Promise<{ deleted: boolean }> {
const deleted = await this.usersService.delete(id);
return { deleted };
}
}
@ApiTags("posts")
@Controller("posts")
export class PostsController {
constructor(private readonly postsService: PostsService) {}
@Get()
@ApiOperation({ summary: "Get all posts" })
@ApiQuery({ name: "search", required: false })
@ApiQuery({ name: "status", required: false, enum: ["draft", "published"] })
async findAll(@Query() query: QueryPostDto) {
return this.postsService.findAll(query);
}
@Get(":id")
@ApiOperation({ summary: "Get post by ID" })
async findOne(@Param("id") id: string) {
const post = await this.postsService.findById(id);
if (post) {
await this.postsService.incrementViews(id);
}
return post;
}
@Post()
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
@ApiOperation({ summary: "Create a new post" })
async create(@Body() dto: CreatePostDto) {
// In real app, get authorId from request user
return this.postsService.create(dto, "current-user-id");
}
@Post(":id/publish")
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
@ApiOperation({ summary: "Publish a post" })
async publish(@Param("id") id: string) {
return this.postsService.publish(id);
}
@Delete(":id")
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
async delete(@Param("id") id: string) {
return { deleted: await this.postsService.delete(id) };
}
}
// ============================================
// Module
// ============================================
@Module({
controllers: [UsersController, PostsController],
providers: [UsersService, PostsService],
exports: [UsersService, PostsService],
})
export class AppModule {}
// ============================================
// Bootstrap
// ============================================
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Enable CORS
app.enableCors();
// Global prefix
app.setGlobalPrefix("api");
// Swagger setup would go here
await app.listen(3000);
console.log("Application running on http://localhost:3000");
}
// bootstrap();
```