后端API开发实战
今天用Claude Code构建一个完整的电商后端API系统,涵盖RESTful API、GraphQL服务、中间件开发、错误处理、API文档生成等核心内容。
项目概述
项目目标
构建电商API后端系统,包括:
- RESTful API: 完整的商品、订单、用户管理接口
- GraphQL服务: 灵活的数据查询接口
- 中间件系统: 认证、授权、日志、限流等
- 错误处理: 统一的错误处理机制
- API文档: 自动生成的Swagger文档
- 数据验证: 请求参数验证和数据清理
- 单元测试: 完整的测试覆盖
技术栈
- 框架: Node.js + Express.js
- 数据库: PostgreSQL + MongoDB(混合使用)
- ORM: Prisma(用于PostgreSQL)
- 认证: JWT + Passport.js
- 验证: Joi + express-validator
- 文档: Swagger/OpenAPI
- GraphQL: Apollo Server
- 测试: Jest + Supertest
- 日志: Winston + Morgan
- 限流: express-rate-limit
- 缓存: Redis
项目结构预览
ecommerce-api/
├── src/
│ ├── config/ # 配置文件
│ │ ├── database.js
│ │ ├── redis.js
│ │ └── passport.js
│ ├── controllers/ # 控制器
│ │ ├── product.controller.js
│ │ ├── order.controller.js
│ │ └── user.controller.js
│ ├── middleware/ # 中间件
│ │ ├── auth.middleware.js
│ │ ├── validate.middleware.js
│ │ ├── error.middleware.js
│ │ ├── logger.middleware.js
│ │ └── rateLimit.middleware.js
│ ├── models/ # Prisma模型
│ │ └── schema.prisma
│ ├── routes/ # RESTful路由
│ │ ├── index.js
│ │ ├── products.js
│ │ ├── orders.js
│ │ └── users.js
│ ├── graphql/ # GraphQL相关
│ │ ├── schema.js
│ │ ├── resolvers.js
│ │ └── typeDefs.js
│ ├── services/ # 业务逻辑层
│ │ ├── product.service.js
│ │ ├── order.service.js
│ │ └── user.service.js
│ ├── utils/ # 工具函数
│ │ ├── validators.js
│ │ ├── helpers.js
│ │ └── constants.js
│ ├── validators/ # 请求验证模式
│ │ ├── product.validator.js
│ │ ├── order.validator.js
│ │ └── user.validator.js
│ ├── tests/ # 测试文件
│ │ ├── unit/
│ │ └── integration/
│ ├── app.js # Express应用配置
│ └── server.js # 服务器入口
├── prisma/ # Prisma配置
│ └── schema.prisma
├── docs/ # API文档
├── .env.example
├── .eslintrc.js
├── .prettierrc
├── package.json
└── README.md
第一阶段:项目初始化和基础架构
第一轮对话
启动Claude Code:
cd ~/projects
mkdir ecommerce-api
cd ecommerce-api
claude
我要创建一个电商后端API系统,包含:
1. RESTful API设计(商品、订单、用户管理)
2. GraphQL服务(灵活查询)
3. JWT认证和授权
4. 中间件系统(日志、限流、CORS)
5. 统一错误处理
6. 请求参数验证
7. Swagger API文档自动生成
8. PostgreSQL数据库(使用Prisma ORM)
9. Redis缓存
10. 单元测试和集成测试
技术栈:
- Node.js + Express
- Prisma + PostgreSQL
- Redis
- JWT + Passport
- Swagger
- Apollo Server(GraphQL)
请帮我创建完整的项目结构和基础配置。
Claude Code会立即分析需求并开始构建:
🤖 Claude: 我将帮你创建一个专业级的电商API后端系统。
让我先创建项目的基础结构和配置文件...
📁 Creating project structure...
✓ Created src/ directory with subdirectories
✓ Created prisma/ directory
✓ Created tests/ directory
✓ Created .gitignore
✓ Created .env.example
✓ Created package.json with all dependencies
✓ Created ESLint and Prettier configurations
✓ Created README.md with project documentation
Now let me set up the configuration files...
项目配置文件
package.json:
{
"name": "ecommerce-api",
"version": "1.0.0",
"description": "Professional E-commerce API Backend",
"main": "src/server.js",
"scripts": {
"start": "node src/server.js",
"dev": "nodemon src/server.js",
"test": "jest --coverage",
"test:watch": "jest --watch",
"prisma:generate": "prisma generate",
"prisma:migrate": "prisma migrate dev",
"prisma:studio": "prisma studio",
"lint": "eslint src/**/*.js",
"lint:fix": "eslint src/**/*.js --fix",
"format": "prettier --write \"src/**/*.js\""
},
"keywords": [
"ecommerce",
"api",
"rest",
"graphql",
"express",
"prisma"
],
"author": "",
"license": "MIT",
"dependencies": {
"@prisma/client": "^5.7.0",
"apollo-server-express": "^3.12.1",
"bcryptjs": "^2.4.3",
"compression": "^1.7.4",
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"express-rate-limit": "^7.1.5",
"express-validator": "^7.0.1",
"graphql": "^16.8.1",
"helmet": "^7.1.0",
"ioredis": "^5.3.2",
"joi": "^17.11.0",
"jsonwebtoken": "^9.0.2",
"morgan": "^1.10.0",
"passport": "^0.7.0",
"passport-jwt": "^4.0.1",
"redis": "^4.6.11",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.0",
"winston": "^3.11.0"
},
"devDependencies": {
"eslint": "^8.55.0",
"jest": "^29.7.0",
"nodemon": "^3.0.2",
"prettier": "^3.1.1",
"prisma": "^5.7.0",
"supertest": "^6.3.3"
}
}
.env.example:
# Server Configuration
NODE_ENV=development
PORT=3000
API_VERSION=v1
# Database
DATABASE_URL="postgresql://user:password@localhost:5432/ecommerce?schema=public"
# Redis
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
# JWT
JWT_SECRET=your-super-secret-jwt-key-change-this-in-production
JWT_EXPIRE=7d
JWT_REFRESH_SECRET=your-refresh-token-secret
JWT_REFRESH_EXPIRE=30d
# CORS
CORS_ORIGIN=http://localhost:3001
# Rate Limiting
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=100
# Logging
LOG_LEVEL=info
LOG_FILE=logs/app.log
# Pagination
DEFAULT_PAGE=1
DEFAULT_LIMIT=20
MAX_LIMIT=100
.gitignore:
# Dependencies
node_modules/
# Environment variables
.env
.env.local
.env.*.local
# Logs
logs/
*.log
npm-debug.log*
# Prisma
prisma/migrations/
# Testing
coverage/
# IDE
.vscode/
.idea/
*.swp
*.swo
# OS
.DS_Store
Thumbs.db
# Build
dist/
build/
Prisma数据库模型
prisma/schema.prisma:
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(uuid())
email String @unique
username String @unique
password String
role Role @default(CUSTOMER)
profile UserProfile?
addresses Address[]
orders Order[]
reviews Review[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("users")
}
model UserProfile {
id String @id @default(uuid())
userId String @unique
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
firstName String?
lastName String?
phone String?
avatar String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("user_profiles")
}
model Address {
id String @id @default(uuid())
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
fullName String
phone String
province String
city String
district String
address String
postalCode String?
isDefault Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("addresses")
}
model Category {
id String @id @default(uuid())
name String @unique
slug String @unique
image String?
parentId String?
parent Category? @relation("CategoryToCategory", fields: [parentId], references: [id], onDelete: SetNull)
children Category[] @relation("CategoryToCategory")
products Product[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("categories")
}
model Product {
id String @id @default(uuid())
name String
slug String @unique
description String?
price Decimal @db.Decimal(10, 2)
comparePrice Decimal? @db.Decimal(10, 2)
sku String @unique
stock Int @default(0)
images String[]
categoryId String
category Category @relation(fields: [categoryId], references: [id])
brand String?
tags String[]
attributes Json?
isActive Boolean @default(true)
reviews Review[]
orderItems OrderItem[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("products")
}
model Order {
id String @id @default(uuid())
orderNumber String @unique
userId String
user User @relation(fields: [userId], references: [id])
items OrderItem[]
status OrderStatus @default(PENDING)
totalAmount Decimal @db.Decimal(10, 2)
discount Decimal @default(0) @db.Decimal(10, 2)
finalAmount Decimal @db.Decimal(10, 2)
shippingAddress Json
paymentMethod String
paymentStatus PaymentStatus @default(PENDING)
notes String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("orders")
}
model OrderItem {
id String @id @default(uuid())
orderId String
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
productId String
product Product @relation(fields: [productId], references: [id])
quantity Int
price Decimal @db.Decimal(10, 2)
totalAmount Decimal @db.Decimal(10, 2)
@@map("order_items")
}
model Review {
id String @id @default(uuid())
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
productId String
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
rating Int
comment String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("reviews")
}
enum Role {
ADMIN
CUSTOMER
}
enum OrderStatus {
PENDING
CONFIRMED
PROCESSING
SHIPPED
DELIVERED
CANCELLED
REFUNDED
}
enum PaymentStatus {
PENDING
COMPLETED
FAILED
REFUNDED
}