api-endpoint-generator
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAPI Endpoint Generator
API端点生成工具
Generate production-ready CRUD API endpoints with validation and type safety.
生成可用于生产环境、带有验证和类型安全的CRUD API端点。
Core Workflow
核心工作流程
- Define resource: Entity name and schema
- Generate routes: POST, GET, PUT/PATCH, DELETE endpoints
- Add validation: Request body/query validation with Zod/Joi
- Type responses: TypeScript interfaces for all responses
- Error handling: Consistent error responses
- Documentation: OpenAPI/Swagger specs
- Examples: Request/response samples
- 定义资源:实体名称和模式
- 生成路由:POST、GET、PUT/PATCH、DELETE端点
- 添加验证:使用Zod/Joi进行请求体/查询参数验证
- 响应类型化:为所有响应定义TypeScript接口
- 错误处理:统一的错误响应格式
- 文档生成:OpenAPI/Swagger规范
- 示例提供:请求/响应示例
Express + TypeScript Pattern
Express + TypeScript 模式
typescript
// types/user.types.ts
export interface User {
id: string;
email: string;
name: string;
role: "user" | "admin";
createdAt: Date;
updatedAt: Date;
}
export interface CreateUserDto {
email: string;
name: string;
password: string;
}
export interface UpdateUserDto {
name?: string;
email?: string;
}
export interface ApiResponse<T> {
success: boolean;
data?: T;
error?: ApiError;
meta?: PaginationMeta;
}
export interface ApiError {
code: string;
message: string;
details?: Record<string, string[]>;
}typescript
// types/user.types.ts
export interface User {
id: string;
email: string;
name: string;
role: "user" | "admin";
createdAt: Date;
updatedAt: Date;
}
export interface CreateUserDto {
email: string;
name: string;
password: string;
}
export interface UpdateUserDto {
name?: string;
email?: string;
}
export interface ApiResponse<T> {
success: boolean;
data?: T;
error?: ApiError;
meta?: PaginationMeta;
}
export interface ApiError {
code: string;
message: string;
details?: Record<string, string[]>;
}Validation Schemas (Zod)
验证模式(Zod)
typescript
// schemas/user.schema.ts
import { z } from "zod";
export const createUserSchema = z.object({
email: z.string().email("Invalid email address"),
name: z.string().min(2, "Name must be at least 2 characters"),
password: z
.string()
.min(8, "Password must be at least 8 characters")
.regex(/[A-Z]/, "Password must contain uppercase letter")
.regex(/[0-9]/, "Password must contain number"),
});
export const updateUserSchema = z
.object({
name: z.string().min(2).optional(),
email: z.string().email().optional(),
})
.refine((data) => Object.keys(data).length > 0, {
message: "At least one field must be provided",
});
export const getUsersQuerySchema = z.object({
page: z.coerce.number().int().positive().default(1),
limit: z.coerce.number().int().min(1).max(100).default(10),
sortBy: z.enum(["name", "email", "createdAt"]).optional(),
sortOrder: z.enum(["asc", "desc"]).default("desc"),
search: z.string().optional(),
});
export type CreateUserDto = z.infer<typeof createUserSchema>;
export type UpdateUserDto = z.infer<typeof updateUserSchema>;
export type GetUsersQuery = z.infer<typeof getUsersQuerySchema>;typescript
// schemas/user.schema.ts
import { z } from "zod";
export const createUserSchema = z.object({
email: z.string().email("Invalid email address"),
name: z.string().min(2, "Name must be at least 2 characters"),
password: z
.string()
.min(8, "Password must be at least 8 characters")
.regex(/[A-Z]/, "Password must contain uppercase letter")
.regex(/[0-9]/, "Password must contain number"),
});
export const updateUserSchema = z
.object({
name: z.string().min(2).optional(),
email: z.string().email().optional(),
})
.refine((data) => Object.keys(data).length > 0, {
message: "At least one field must be provided",
});
export const getUsersQuerySchema = z.object({
page: z.coerce.number().int().positive().default(1),
limit: z.coerce.number().int().min(1).max(100).default(10),
sortBy: z.enum(["name", "email", "createdAt"]).optional(),
sortOrder: z.enum(["asc", "desc"]).default("desc"),
search: z.string().optional(),
});
export type CreateUserDto = z.infer<typeof createUserSchema>;
export type UpdateUserDto = z.infer<typeof updateUserSchema>;
export type GetUsersQuery = z.infer<typeof getUsersQuerySchema>;CRUD Route Handlers
CRUD路由处理器
typescript
// routes/users.routes.ts
import { Router } from "express";
import { UserController } from "../controllers/user.controller";
import { validateRequest } from "../middleware/validate";
import { authenticate } from "../middleware/auth";
import {
createUserSchema,
updateUserSchema,
getUsersQuerySchema,
} from "../schemas/user.schema";
const router = Router();
const controller = new UserController();
// Create
router.post(
"/",
authenticate,
validateRequest({ body: createUserSchema }),
controller.create
);
// Read (list)
router.get(
"/",
authenticate,
validateRequest({ query: getUsersQuerySchema }),
controller.list
);
// Read (single)
router.get("/:id", authenticate, controller.getById);
// Update
router.patch(
"/:id",
authenticate,
validateRequest({ body: updateUserSchema }),
controller.update
);
// Delete
router.delete("/:id", authenticate, controller.delete);
export default router;typescript
// routes/users.routes.ts
import { Router } from "express";
import { UserController } from "../controllers/user.controller";
import { validateRequest } from "../middleware/validate";
import { authenticate } from "../middleware/auth";
import {
createUserSchema,
updateUserSchema,
getUsersQuerySchema,
} from "../schemas/user.schema";
const router = Router();
const controller = new UserController();
// 创建
router.post(
"/",
authenticate,
validateRequest({ body: createUserSchema }),
controller.create
);
// 读取(列表)
router.get(
"/",
authenticate,
validateRequest({ query: getUsersQuerySchema }),
controller.list
);
// 读取(单个)
router.get("/:id", authenticate, controller.getById);
// 更新
router.patch(
"/:id",
authenticate,
validateRequest({ body: updateUserSchema }),
controller.update
);
// 删除
router.delete("/:id", authenticate, controller.delete);
export default router;Controller Implementation
控制器实现
typescript
// controllers/user.controller.ts
import { Request, Response, NextFunction } from "express";
import { UserService } from "../services/user.service";
import {
CreateUserDto,
UpdateUserDto,
GetUsersQuery,
} from "../types/user.types";
import { ApiResponse } from "../types/api.types";
export class UserController {
private service = new UserService();
create = async (
req: Request<{}, {}, CreateUserDto>,
res: Response<ApiResponse<User>>,
next: NextFunction
) => {
try {
const user = await this.service.create(req.body);
res.status(201).json({
success: true,
data: user,
});
} catch (error) {
next(error);
}
};
list = async (
req: Request<{}, {}, {}, GetUsersQuery>,
res: Response<ApiResponse<User[]>>,
next: NextFunction
) => {
try {
const { page, limit, sortBy, sortOrder, search } = req.query;
const result = await this.service.findAll({
page,
limit,
sortBy,
sortOrder,
search,
});
res.json({
success: true,
data: result.users,
meta: {
page: result.page,
limit: result.limit,
total: result.total,
totalPages: result.totalPages,
},
});
} catch (error) {
next(error);
}
};
getById = async (
req: Request<{ id: string }>,
res: Response<ApiResponse<User>>,
next: NextFunction
) => {
try {
const user = await this.service.findById(req.params.id);
if (!user) {
return res.status(404).json({
success: false,
error: {
code: "USER_NOT_FOUND",
message: "User not found",
},
});
}
res.json({
success: true,
data: user,
});
} catch (error) {
next(error);
}
};
update = async (
req: Request<{ id: string }, {}, UpdateUserDto>,
res: Response<ApiResponse<User>>,
next: NextFunction
) => {
try {
const user = await this.service.update(req.params.id, req.body);
if (!user) {
return res.status(404).json({
success: false,
error: {
code: "USER_NOT_FOUND",
message: "User not found",
},
});
}
res.json({
success: true,
data: user,
});
} catch (error) {
next(error);
}
};
delete = async (
req: Request<{ id: string }>,
res: Response<ApiResponse<void>>,
next: NextFunction
) => {
try {
const deleted = await this.service.delete(req.params.id);
if (!deleted) {
return res.status(404).json({
success: false,
error: {
code: "USER_NOT_FOUND",
message: "User not found",
},
});
}
res.status(204).send();
} catch (error) {
next(error);
}
};
}typescript
// controllers/user.controller.ts
import { Request, Response, NextFunction } from "express";
import { UserService } from "../services/user.service";
import {
CreateUserDto,
UpdateUserDto,
GetUsersQuery,
} from "../types/user.types";
import { ApiResponse } from "../types/api.types";
export class UserController {
private service = new UserService();
create = async (
req: Request<{}, {}, CreateUserDto>,
res: Response<ApiResponse<User>>,
next: NextFunction
) => {
try {
const user = await this.service.create(req.body);
res.status(201).json({
success: true,
data: user,
});
} catch (error) {
next(error);
}
};
list = async (
req: Request<{}, {}, {}, GetUsersQuery>,
res: Response<ApiResponse<User[]>>,
next: NextFunction
) => {
try {
const { page, limit, sortBy, sortOrder, search } = req.query;
const result = await this.service.findAll({
page,
limit,
sortBy,
sortOrder,
search,
});
res.json({
success: true,
data: result.users,
meta: {
page: result.page,
limit: result.limit,
total: result.total,
totalPages: result.totalPages,
},
});
} catch (error) {
next(error);
}
};
getById = async (
req: Request<{ id: string }>,
res: Response<ApiResponse<User>>,
next: NextFunction
) => {
try {
const user = await this.service.findById(req.params.id);
if (!user) {
return res.status(404).json({
success: false,
error: {
code: "USER_NOT_FOUND",
message: "用户未找到",
},
});
}
res.json({
success: true,
data: user,
});
} catch (error) {
next(error);
}
};
update = async (
req: Request<{ id: string }, {}, UpdateUserDto>,
res: Response<ApiResponse<User>>,
next: NextFunction
) => {
try {
const user = await this.service.update(req.params.id, req.body);
if (!user) {
return res.status(404).json({
success: false,
error: {
code: "USER_NOT_FOUND",
message: "用户未找到",
},
});
}
res.json({
success: true,
data: user,
});
} catch (error) {
next(error);
}
};
delete = async (
req: Request<{ id: string }>,
res: Response<ApiResponse<void>>,
next: NextFunction
) => {
try {
const deleted = await this.service.delete(req.params.id);
if (!deleted) {
return res.status(404).json({
success: false,
error: {
code: "USER_NOT_FOUND",
message: "用户未找到",
},
});
}
res.status(204).send();
} catch (error) {
next(error);
}
};
}Validation Middleware
验证中间件
typescript
// middleware/validate.ts
import { Request, Response, NextFunction } from "express";
import { ZodSchema } from "zod";
interface ValidationSchemas {
body?: ZodSchema;
query?: ZodSchema;
params?: ZodSchema;
}
export const validateRequest = (schemas: ValidationSchemas) => {
return (req: Request, res: Response, next: NextFunction) => {
try {
if (schemas.body) {
req.body = schemas.body.parse(req.body);
}
if (schemas.query) {
req.query = schemas.query.parse(req.query);
}
if (schemas.params) {
req.params = schemas.params.parse(req.params);
}
next();
} catch (error) {
if (error instanceof z.ZodError) {
return res.status(400).json({
success: false,
error: {
code: "VALIDATION_ERROR",
message: "Invalid request data",
details: error.flatten().fieldErrors,
},
});
}
next(error);
}
};
};typescript
// middleware/validate.ts
import { Request, Response, NextFunction } from "express";
import { ZodSchema } from "zod";
interface ValidationSchemas {
body?: ZodSchema;
query?: ZodSchema;
params?: ZodSchema;
}
export const validateRequest = (schemas: ValidationSchemas) => {
return (req: Request, res: Response, next: NextFunction) => {
try {
if (schemas.body) {
req.body = schemas.body.parse(req.body);
}
if (schemas.query) {
req.query = schemas.query.parse(req.query);
}
if (schemas.params) {
req.params = schemas.params.parse(req.params);
}
next();
} catch (error) {
if (error instanceof z.ZodError) {
return res.status(400).json({
success: false,
error: {
code: "VALIDATION_ERROR",
message: "请求数据无效",
details: error.flatten().fieldErrors,
},
});
}
next(error);
}
};
};NestJS Pattern
NestJS模式
typescript
// users/users.controller.ts
import {
Controller,
Get,
Post,
Put,
Delete,
Body,
Param,
Query,
} from "@nestjs/common";
import { ApiTags, ApiOperation, ApiResponse } from "@nestjs/swagger";
import { UsersService } from "./users.service";
import { CreateUserDto, UpdateUserDto, GetUsersQueryDto } from "./dto";
@ApiTags("users")
@Controller("users")
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Post()
@ApiOperation({ summary: "Create user" })
@ApiResponse({ status: 201, description: "User created" })
@ApiResponse({ status: 400, description: "Validation error" })
async create(@Body() dto: CreateUserDto) {
return this.usersService.create(dto);
}
@Get()
@ApiOperation({ summary: "List users" })
async findAll(@Query() query: GetUsersQueryDto) {
return this.usersService.findAll(query);
}
@Get(":id")
@ApiOperation({ summary: "Get user by ID" })
async findOne(@Param("id") id: string) {
return this.usersService.findOne(id);
}
@Put(":id")
@ApiOperation({ summary: "Update user" })
async update(@Param("id") id: string, @Body() dto: UpdateUserDto) {
return this.usersService.update(id, dto);
}
@Delete(":id")
@ApiOperation({ summary: "Delete user" })
async remove(@Param("id") id: string) {
return this.usersService.remove(id);
}
}typescript
// users/users.controller.ts
import {
Controller,
Get,
Post,
Put,
Delete,
Body,
Param,
Query,
} from "@nestjs/common";
import { ApiTags, ApiOperation, ApiResponse } from "@nestjs/swagger";
import { UsersService } from "./users.service";
import { CreateUserDto, UpdateUserDto, GetUsersQueryDto } from "./dto";
@ApiTags("users")
@Controller("users")
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Post()
@ApiOperation({ summary: "创建用户" })
@ApiResponse({ status: 201, description: "用户已创建" })
@ApiResponse({ status: 400, description: "验证错误" })
async create(@Body() dto: CreateUserDto) {
return this.usersService.create(dto);
}
@Get()
@ApiOperation({ summary: "列出用户" })
async findAll(@Query() query: GetUsersQueryDto) {
return this.usersService.findAll(query);
}
@Get(":id")
@ApiOperation({ summary: "根据ID获取用户" })
async findOne(@Param("id") id: string) {
return this.usersService.findOne(id);
}
@Put(":id")
@ApiOperation({ summary: "更新用户" })
async update(@Param("id") id: string, @Body() dto: UpdateUserDto) {
return this.usersService.update(id, dto);
}
@Delete(":id")
@ApiOperation({ summary: "删除用户" })
async remove(@Param("id") id: string) {
return this.usersService.remove(id);
}
}FastAPI Pattern (Python)
FastAPI模式(Python)
python
undefinedpython
undefinedrouters/users.py
routers/users.py
from fastapi import APIRouter, Depends, HTTPException, Query
from typing import List, Optional
from pydantic import BaseModel, EmailStr, Field
router = APIRouter(prefix="/users", tags=["users"])
class CreateUserDto(BaseModel):
email: EmailStr
name: str = Field(..., min_length=2)
password: str = Field(..., min_length=8)
class UserResponse(BaseModel):
id: str
email: str
name: str
role: str
created_at: datetime
class PaginatedResponse(BaseModel):
data: List[UserResponse]
total: int
page: int
limit: int
@router.post("/", status_code=201, response_model=UserResponse)
async def create_user(dto: CreateUserDto, service: UserService = Depends()):
return await service.create(dto)
@router.get("/", response_model=PaginatedResponse)
async def list_users(
page: int = Query(1, ge=1),
limit: int = Query(10, ge=1, le=100),
search: Optional[str] = None,
service: UserService = Depends()
):
return await service.find_all(page, limit, search)
undefinedfrom fastapi import APIRouter, Depends, HTTPException, Query
from typing import List, Optional
from pydantic import BaseModel, EmailStr, Field
router = APIRouter(prefix="/users", tags=["users"])
class CreateUserDto(BaseModel):
email: EmailStr
name: str = Field(..., min_length=2)
password: str = Field(..., min_length=8)
class UserResponse(BaseModel):
id: str
email: str
name: str
role: str
created_at: datetime
class PaginatedResponse(BaseModel):
data: List[UserResponse]
total: int
page: int
limit: int
@router.post("/", status_code=201, response_model=UserResponse)
async def create_user(dto: CreateUserDto, service: UserService = Depends()):
return await service.create(dto)
@router.get("/", response_model=PaginatedResponse)
async def list_users(
page: int = Query(1, ge=1),
limit: int = Query(10, ge=1, le=100),
search: Optional[str] = None,
service: UserService = Depends()
):
return await service.find_all(page, limit, search)
undefinedResponse Format Standards
响应格式标准
typescript
// Success Response
{
"success": true,
"data": { ... },
"meta": {
"page": 1,
"limit": 10,
"total": 50,
"totalPages": 5
}
}
// Error Response
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request data",
"details": {
"email": ["Invalid email address"],
"password": ["Password must contain uppercase letter"]
}
}
}typescript
// 成功响应
{
"success": true,
"data": { ... },
"meta": {
"page": 1,
"limit": 10,
"total": 50,
"totalPages": 5
}
}
// 错误响应
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "请求数据无效",
"details": {
"email": ["Invalid email address"],
"password": ["Password must contain uppercase letter"]
}
}
}Status Codes
状态码
- 200: Success (GET, PUT)
- 201: Created (POST)
- 204: No Content (DELETE)
- 400: Validation Error
- 401: Unauthorized
- 403: Forbidden
- 404: Not Found
- 409: Conflict
- 500: Server Error
- 200: 成功(GET、PUT)
- 201: 创建成功(POST)
- 204: 无内容(DELETE)
- 400: 验证错误
- 401: 未授权
- 403: 禁止访问
- 404: 未找到
- 409: 冲突
- 500: 服务器错误
Best Practices
最佳实践
- Type everything: Request, response, DTOs, errors
- Validate early: Before hitting service layer
- Consistent responses: Same structure everywhere
- HTTP semantics: Use correct status codes
- Error details: Include validation errors
- Pagination: Always paginate lists
- Filtering/sorting: Support common queries
- Documentation: OpenAPI/Swagger specs
- 全面类型化:请求、响应、DTO、错误都要有类型定义
- 尽早验证:在到达服务层之前完成验证
- 统一响应:所有接口使用相同的响应结构
- HTTP语义化:使用正确的状态码
- 错误详情:包含验证错误的具体信息
- 分页处理:列表接口始终支持分页
- 过滤与排序:支持常见的查询参数
- 文档生成:提供OpenAPI/Swagger规范
Output Checklist
输出检查清单
- Route definitions with HTTP methods
- Request validation schemas
- TypeScript types for all DTOs
- Controller handlers with error handling
- Consistent response format
- Pagination for list endpoints
- HTTP status codes correctly used
- Error response format
- OpenAPI/Swagger documentation
- Usage examples with curl/requests
- 包含HTTP方法的路由定义
- 请求验证模式
- 所有DTO的TypeScript类型
- 带有错误处理的控制器处理器
- 统一的响应格式
- 列表端点的分页功能
- 正确使用HTTP状态码
- 错误响应格式
- OpenAPI/Swagger文档
- 包含curl/请求示例的使用说明