TypeORM CRUD + Swagger — 博客文章管理

知识库
知识库文档
/tech-stacks/nestjs/examples/TypeORM CRUD + Swagger — 博客文章管理.md

文档

NestJS TypeORM CRUD + Swagger 文档

目标

用 TypeORM 操作 SQLite 数据库,配合 Swagger 自动生成交互式 API 文档。

模块代码

src/posts/entities/post.entity.ts

import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn } from 'typeorm';
import { ApiProperty } from '@nestjs/swagger';

@Entity()
export class Post {
  @ApiProperty({ description: '文章ID', example: 1 })
  @PrimaryGeneratedColumn()
  id: number;

  @ApiProperty({ description: '标题', example: '毕设心得' })
  @Column({ length: 100 })
  title: string;

  @ApiProperty({ description: '内容', example: '这是正文...' })
  @Column('text')
  content: string;

  @ApiProperty({ description: '作者', example: '张三' })
  @Column({ length: 50 })
  author: string;

  @ApiProperty({ description: '创建时间' })
  @CreateDateColumn()
  createdAt: Date;
}

src/posts/dto/create-post.dto.ts

import { ApiProperty } from '@nestjs/swagger';
import { IsString, MinLength, MaxLength } from 'class-validator';

export class CreatePostDto {
  @ApiProperty({ description: '文章标题', minLength: 2, maxLength: 100 })
  @IsString()
  @MinLength(2)
  @MaxLength(100)
  title: string;

  @ApiProperty({ description: '文章内容', minLength: 10 })
  @IsString()
  @MinLength(10)
  content: string;

  @ApiProperty({ description: '作者名', maxLength: 50 })
  @IsString()
  @MaxLength(50)
  author: string;
}

src/posts/posts.service.ts

import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, Like } from 'typeorm';
import { Post } from './entities/post.entity';
import { CreatePostDto } from './dto/create-post.dto';

@Injectable()
export class PostsService {
  constructor(
    @InjectRepository(Post)
    private postsRepo: Repository<Post>,
  ) {}

  async create(dto: CreatePostDto): Promise<Post> {
    return this.postsRepo.save(this.postsRepo.create(dto));
  }

  async findAll(page = 1, limit = 10, keyword?: string) {
    const where = keyword
      ? [{ title: Like(`%${keyword}%`) }, { author: Like(`%${keyword}%`) }]
      : {};
    const [data, total] = await this.postsRepo.findAndCount({
      where,
      skip: (page - 1) * limit,
      take: limit,
      order: { createdAt: 'DESC' },
    });
    return { data, total, page, limit, totalPages: Math.ceil(total / limit) };
  }

  async findOne(id: number): Promise<Post> {
    const post = await this.postsRepo.findOne({ where: { id } });
    if (!post) throw new NotFoundException(`文章 #${id} 不存在`);
    return post;
  }

  async update(id: number, dto: Partial<CreatePostDto>) {
    const post = await this.findOne(id);
    Object.assign(post, dto);
    return this.postsRepo.save(post);
  }

  async remove(id: number) {
    const post = await this.findOne(id);
    return this.postsRepo.remove(post);
  }
}

src/posts/posts.controller.ts

import { Controller, Get, Post, Body, Param, Delete, Put, Query, ParseIntPipe } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiQuery, ApiResponse } from '@nestjs/swagger';
import { PostsService } from './posts.service';
import { CreatePostDto } from './dto/create-post.dto';

@ApiTags('文章管理')
@Controller('posts')
export class PostsController {
  constructor(private readonly postsService: PostsService) {}

  @Post()
  @ApiOperation({ summary: '创建文章' })
  @ApiResponse({ status: 201, description: '创建成功' })
  create(@Body() dto: CreatePostDto) {
    return this.postsService.create(dto);
  }

  @Get()
  @ApiOperation({ summary: '获取文章列表(支持分页+搜索)' })
  @ApiQuery({ name: 'page', required: false, example: 1 })
  @ApiQuery({ name: 'limit', required: false, example: 10 })
  @ApiQuery({ name: 'q', required: false, description: '搜索关键词' })
  findAll(
    @Query('page') page = 1,
    @Query('limit') limit = 10,
    @Query('q') q?: string,
  ) {
    return this.postsService.findAll(+page, +limit, q);
  }

  @Get(':id')
  @ApiOperation({ summary: '获取单篇文章' })
  findOne(@Param('id', ParseIntPipe) id: number) {
    return this.postsService.findOne(id);
  }

  @Put(':id')
  @ApiOperation({ summary: '更新文章' })
  update(@Param('id', ParseIntPipe) id: number, @Body() dto: Partial<CreatePostDto>) {
    return this.postsService.update(id, dto);
  }

  @Delete(':id')
  @ApiOperation({ summary: '删除文章' })
  remove(@Param('id', ParseIntPipe) id: number) {
    return this.postsService.remove(id);
  }
}

src/posts/posts.module.ts

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { PostsService } from './posts.service';
import { PostsController } from './posts.controller';
import { Post } from './entities/post.entity';

@Module({
  imports: [TypeOrmModule.forFeature([Post])],
  controllers: [PostsController],
  providers: [PostsService],
})
export class PostsModule {}

app.module.ts 数据库配置

TypeOrmModule.forRoot({
  type: 'sqlite',
  database: 'blog.db',
  entities: [__dirname + '/**/*.entity{.ts,.js}'],
  synchronize: true, // 开发环境自动建表
}),

运行

npm run start:dev
# Swagger 文档: http://localhost:3000/api-docs
# 可在 Swagger UI 上直接测试所有接口!

预期效果

  • Swagger UI 展示所有 API,可直接点 Try it out 测试
  • 分页查询支持 keyword 模糊搜索
  • SQLite 零配置,blog.db 文件随项目携带

信息

路径
/tech-stacks/nestjs/examples/TypeORM CRUD + Swagger — 博客文章管理.md
更新时间
2026/5/30