$npx -y skills add virgo777/buddyme --skill backend-patterns后端架构模式、API 设计、数据库优化以及针对 Node.js、Express 和 Next.js API 路由的服务端最佳实践。
| 1 | # 后端开发模式 (Backend Development Patterns) |
| 2 | |
| 3 | 用于构建可扩展服务端应用的后端架构模式与最佳实践。 |
| 4 | |
| 5 | ## 何时激活 (When to Activate) |
| 6 | |
| 7 | - 设计 REST 或 GraphQL API 端点时 |
| 8 | - 实现仓储层(Repository)、服务层(Service)或控制层(Controller)时 |
| 9 | - 优化数据库查询(N+1 问题、索引、连接池)时 |
| 10 | - 添加缓存(Redis、内存缓存、HTTP 缓存头)时 |
| 11 | - 设置后台作业(Background jobs)或异步处理时 |
| 12 | - 为 API 构建错误处理与数据校验机制时 |
| 13 | - 编写中间件(身份验证、日志记录、限流)时 |
| 14 | |
| 15 | ## API 设计模式 |
| 16 | |
| 17 | ### RESTful API 结构 |
| 18 | |
| 19 | ```typescript |
| 20 | // ✅ 基于资源的 URL |
| 21 | GET /api/markets # 获取资源列表 |
| 22 | GET /api/markets/:id # 获取单个资源 |
| 23 | POST /api/markets # 创建资源 |
| 24 | PUT /api/markets/:id # 替换资源 |
| 25 | PATCH /api/markets/:id # 更新资源 |
| 26 | DELETE /api/markets/:id # 删除资源 |
| 27 | |
| 28 | // ✅ 使用查询参数进行过滤、排序、分页 |
| 29 | GET /api/markets?status=active&sort=volume&limit=20&offset=0 |
| 30 | ``` |
| 31 | |
| 32 | ### 仓储模式 (Repository Pattern) |
| 33 | |
| 34 | ```typescript |
| 35 | // 抽象数据访问逻辑 |
| 36 | interface MarketRepository { |
| 37 | findAll(filters?: MarketFilters): Promise<Market[]> |
| 38 | findById(id: string): Promise<Market | null> |
| 39 | create(data: CreateMarketDto): Promise<Market> |
| 40 | update(id: string, data: UpdateMarketDto): Promise<Market> |
| 41 | delete(id: string): Promise<void> |
| 42 | } |
| 43 | |
| 44 | class SupabaseMarketRepository implements MarketRepository { |
| 45 | async findAll(filters?: MarketFilters): Promise<Market[]> { |
| 46 | let query = supabase.from('markets').select('*') |
| 47 | |
| 48 | if (filters?.status) { |
| 49 | query = query.eq('status', filters.status) |
| 50 | } |
| 51 | |
| 52 | if (filters?.limit) { |
| 53 | query = query.limit(filters.limit) |
| 54 | } |
| 55 | |
| 56 | const { data, error } = await query |
| 57 | |
| 58 | if (error) throw new Error(error.message) |
| 59 | return data |
| 60 | } |
| 61 | |
| 62 | // 其他方法... |
| 63 | } |
| 64 | ``` |
| 65 | |
| 66 | ### 服务层模式 (Service Layer Pattern) |
| 67 | |
| 68 | ```typescript |
| 69 | // 将业务逻辑与数据访问分离 |
| 70 | class MarketService { |
| 71 | constructor(private marketRepo: MarketRepository) {} |
| 72 | |
| 73 | async searchMarkets(query: string, limit: number = 10): Promise<Market[]> { |
| 74 | // 业务逻辑 |
| 75 | const embedding = await generateEmbedding(query) |
| 76 | const results = await this.vectorSearch(embedding, limit) |
| 77 | |
| 78 | // 获取完整数据 |
| 79 | const markets = await this.marketRepo.findByIds(results.map(r => r.id)) |
| 80 | |
| 81 | // 按相似度排序 |
| 82 | return markets.sort((a, b) => { |
| 83 | const scoreA = results.find(r => r.id === a.id)?.score || 0 |
| 84 | const scoreB = results.find(r => r.id === b.id)?.score || 0 |
| 85 | return scoreA - scoreB |
| 86 | }) |
| 87 | } |
| 88 | |
| 89 | private async vectorSearch(embedding: number[], limit: number) { |
| 90 | // 向量搜索实现 |
| 91 | } |
| 92 | } |
| 93 | ``` |
| 94 | |
| 95 | ### 中间件模式 (Middleware Pattern) |
| 96 | |
| 97 | ```typescript |
| 98 | // 请求/响应处理流水线 |
| 99 | export function withAuth(handler: NextApiHandler): NextApiHandler { |
| 100 | return async (req, res) => { |
| 101 | const token = req.headers.authorization?.replace('Bearer ', '') |
| 102 | |
| 103 | if (!token) { |
| 104 | return res.status(401).json({ error: 'Unauthorized' }) |
| 105 | } |
| 106 | |
| 107 | try { |
| 108 | const user = await verifyToken(token) |
| 109 | req.user = user |
| 110 | return handler(req, res) |
| 111 | } catch (error) { |
| 112 | return res.status(401).json({ error: 'Invalid token' }) |
| 113 | } |
| 114 | } |
| 115 | } |
| 116 | |
| 117 | // 使用示例 |
| 118 | export default withAuth(async (req, res) => { |
| 119 | // Handler 可以访问 req.user |
| 120 | }) |
| 121 | ``` |
| 122 | |
| 123 | ## 数据库模式 |
| 124 | |
| 125 | ### 查询优化 |
| 126 | |
| 127 | ```typescript |
| 128 | // ✅ 推荐:仅选择需要的列 |
| 129 | const { data } = await supabase |
| 130 | .from('markets') |
| 131 | .select('id, name, status, volume') |
| 132 | .eq('status', 'active') |
| 133 | .order('volume', { ascending: false }) |
| 134 | .limit(10) |
| 135 | |
| 136 | // ❌ 糟糕:选择所有列 |
| 137 | const { data } = await supabase |
| 138 | .from('markets') |
| 139 | .select('*') |
| 140 | ``` |
| 141 | |
| 142 | ### 防止 N+1 查询 |
| 143 | |
| 144 | ```typescript |
| 145 | // ❌ 糟糕:N+1 查询问题 |
| 146 | const markets = await getMarkets() |
| 147 | for (const market of markets) { |
| 148 | market.creator = await getUser(market.creator_id) // 产生 N 次查询 |
| 149 | } |
| 150 | |
| 151 | // ✅ 推荐:批量获取 |
| 152 | const markets = await getMarkets() |
| 153 | const creatorIds = markets.map(m => m.creator_id) |
| 154 | const creators = await getUsers(creatorIds) // 1 次查询 |
| 155 | const creatorMap = new Map(creators.map(c => [c.id, c])) |
| 156 | |
| 157 | markets.forEach(market => { |
| 158 | market.creator = creatorMap.get(market.creator_id) |
| 159 | }) |
| 160 | ``` |
| 161 | |
| 162 | ### 事务模式 (Transaction Pattern) |
| 163 | |
| 164 | ```typescript |
| 165 | async function createMarketWithPosition( |
| 166 | marketData: CreateMarketDto, |
| 167 | positionData: CreatePositionDto |
| 168 | ) { |
| 169 | // 使用 Supabase 事务 (RPC 调用) |
| 170 | const { data, error } = await supabase.rpc('create_market_with_position', { |
| 171 | market_data: marketData, |
| 172 | position_data: positionData |
| 173 | }) |
| 174 | |
| 175 | if (error) throw new Error('Transaction failed') |
| 176 | return data |
| 177 | } |
| 178 | |
| 179 | // Supabase 中的 SQL 函数 |
| 180 | CREATE OR REPLACE FUNCTION create_market_with_position( |
| 181 | market_data jsonb, |
| 182 | position_data jsonb |
| 183 | ) |
| 184 | RETURNS jsonb |
| 185 | LANGUAGE plpgsql |
| 186 | AS $$ |
| 187 | BEGIN |
| 188 | -- 自动开始事务 |
| 189 | INSERT INTO markets VALUES (market_data); |
| 190 | INSERT INTO positions VALUES (position_data); |
| 191 | RETURN jsonb_build_object('success', true); |
| 192 | EXCEPTION |
| 193 | WHEN OTHERS THEN |
| 194 | -- 发生错误时自动回滚 |
| 195 | RETURN jsonb_build_object('success', false, 'error', SQLERRM); |
| 196 | END; |
| 197 | $$; |
| 198 | ``` |
| 199 | |
| 200 | ## 缓存策略 |
| 201 | |
| 202 | ### Redis 缓存层 |
| 203 | |
| 204 | ```typescript |
| 205 | class CachedMarketRepository implements MarketRepository { |
| 206 | constructor( |
| 207 | private baseRepo: MarketRepository, |
| 208 | private redis: RedisClient |
| 209 | ) {} |
| 210 | |
| 211 | async findById(id: string): Promise<Market | null> { |
| 212 | // 首先检查缓存 |
| 213 | const cached = await this.redis.get(`market:${id}`) |
| 214 | |
| 215 | if (cached) { |
| 216 | return JSON.parse(cached) |