library-picturebook-activity/.claude/skills/backend-api.md
2026-01-15 16:35:00 +08:00

5.6 KiB
Raw Blame History

后端接口生成规范

概述

本规范用于快速生成 NestJS 后端接口,包含:

  • Controller路由定义
  • Service业务逻辑
  • DTO参数校验
  • 前端 API 调用

快速生成指令格式

请生成后端接口:

模块名称xxx
接口路径GET/POST /api/xxx
功能描述xxx

查询参数:
- 参数1类型必填/选填)
- 参数2类型必填/选填)

返回字段:
- 字段1来源表.字段)
- 字段2关联表.字段)

关联查询:
- 表1 -> 表2关联字段

排序:字段名 + 排序方式
分页:是/否

文件结构

backend/src/模块名/
├── 模块名.module.ts      # 模块定义
├── 模块名.controller.ts  # 路由控制器
├── 模块名.service.ts     # 业务逻辑
└── dto/
    ├── query-xxx.dto.ts  # 查询参数 DTO
    └── create-xxx.dto.ts # 创建参数 DTO

frontend/src/api/
└── 模块名.ts             # 前端 API 调用

Controller 模板

import { Controller, Get, Query, Param, UseGuards } from '@nestjs/common';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
import { XxxService } from './xxx.service';
import { QueryXxxDto } from './dto/query-xxx.dto';

@Controller('api/xxx')
@UseGuards(JwtAuthGuard)
export class XxxController {
  constructor(private readonly xxxService: XxxService) {}

  @Get(':id/list')
  async getList(
    @Param('id') id: string,
    @Query() queryDto: QueryXxxDto,
  ) {
    return this.xxxService.findAll(+id, queryDto);
  }
}

Service 模板

import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { QueryXxxDto } from './dto/query-xxx.dto';

@Injectable()
export class XxxService {
  constructor(private prisma: PrismaService) {}

  async findAll(parentId: number, queryDto: QueryXxxDto) {
    const { page = 1, pageSize = 10, ...filters } = queryDto;
    const skip = (page - 1) * pageSize;

    // 构建查询条件
    const where: any = { parentId };

    if (filters.field1) {
      where.field1 = { contains: filters.field1 };
    }

    const [list, total] = await Promise.all([
      this.prisma.table.findMany({
        where,
        skip,
        take: pageSize,
        orderBy: { sortField: 'desc' },
        include: {
          // 关联查询
        },
      }),
      this.prisma.table.count({ where }),
    ]);

    return { list, total, page, pageSize };
  }
}

DTO 模板

import { IsOptional, IsString, IsInt, Min } from 'class-validator';
import { Type } from 'class-transformer';

export class QueryXxxDto {
  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  page?: number = 1;

  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  pageSize?: number = 10;

  @IsOptional()
  @IsString()
  field1?: string;

  @IsOptional()
  @IsString()
  field2?: string;
}

前端 API 模板

import request from '@/utils/request'

export interface QueryXxxParams {
  page?: number
  pageSize?: number
  field1?: string
  field2?: string
}

export interface XxxItem {
  id: number
  // ... 其他字段
}

export interface XxxListResponse {
  list: XxxItem[]
  total: number
  page: number
  pageSize: number
}

export const xxxApi = {
  getList(parentId: number, params: QueryXxxParams): Promise<XxxListResponse> {
    return request.get(`/api/xxx/${parentId}/list`, { params })
  },
}

Prisma 关联查询示例

常用关联模式

// 用户信息 + 租户 + 学生班级年级
user: {
  include: {
    tenant: {
      select: { id: true, name: true },
    },
    student: {
      include: {
        class: {
          include: {
            grade: {
              select: { id: true, name: true },
            },
          },
        },
      },
    },
  },
}

// 指导老师列表
teachers: {
  include: {
    user: {
      select: { id: true, username: true, nickname: true },
    },
  },
}

// 报名信息 + 用户 + 团队
registration: {
  include: {
    user: {
      select: { id: true, username: true, nickname: true },
    },
    team: {
      select: { id: true, teamName: true },
    },
  },
}

示例:赛果发布详情接口

请生成后端接口:

模块名称results已存在需修改
接口路径GET /api/contests/:id/results/works
功能描述:获取赛事的作品列表(用于赛果发布)

查询参数:
- pagenumber选填默认1
- pageSizenumber选填默认10
- workNostring选填作品编号模糊搜索
- accountNostring选填报名账号模糊搜索

返回字段:
- id, workNo, title, finalScore作品表
- registration.user.nickname, username用户表
- registration.user.tenant.name租户表
- registration.user.student.class.name, grade.name班级年级
- registration.teachers[].user.nickname指导老师

关联查询:
- ContestWork -> ContestRegistrationregistrationId
- ContestRegistration -> UseruserId
- User -> TenanttenantId
- User -> Student -> Class -> Grade
- ContestRegistration -> ContestRegistrationTeacher -> User

排序finalScore DESC
分页:是

注意事项

  1. 权限控制Controller 需要添加 @UseGuards(JwtAuthGuard) 和权限装饰器
  2. 参数校验DTO 使用 class-validator 进行校验
  3. 分页处理:统一使用 page/pageSize 参数
  4. 空值处理:查询条件为空时不添加到 where 条件
  5. 关联数据:使用 Prisma 的 include 进行关联查询
  6. 性能优化:只 select 需要的字段,避免查询过多数据
  7. 错误处理Service 层抛出 NestJS 内置异常