Claude-skill-registry api
RESTful API design patterns and best practices. Use when creating endpoints, designing APIs, or implementing routes.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/api" ~/.claude/skills/majiayu000-claude-skill-registry-api && rm -rf "$T"
manifest:
skills/data/api/SKILL.mdsafety · automated scan (low risk)
This is a pattern-based risk scan, not a security review. Our crawler flagged:
- references .env files
Always read a skill's source content before installing. Patterns alone don't mean the skill is malicious — but they warrant attention.
source content
API 开发技能
本技能提供 RESTful API 开发的最佳实践和模式。
触发条件
- 创建 API 端点
- 设计 REST API
- 实现后端路由
- 处理请求/响应
- API 版本控制
RESTful 设计原则
URL 设计
# 资源命名 - 使用名词复数 GET /api/v1/users # 获取用户列表 GET /api/v1/users/:id # 获取单个用户 POST /api/v1/users # 创建用户 PUT /api/v1/users/:id # 更新用户(完整替换) PATCH /api/v1/users/:id # 更新用户(部分更新) DELETE /api/v1/users/:id # 删除用户 # 嵌套资源 GET /api/v1/users/:id/orders # 用户的订单 GET /api/v1/users/:id/orders/:orderId # 用户的特定订单 # 动作资源 POST /api/v1/users/:id/activate # 激活用户 POST /api/v1/orders/:id/cancel # 取消订单
HTTP 方法语义
| 方法 | 语义 | 幂等 | 安全 |
|---|---|---|---|
| GET | 读取资源 | ✅ | ✅ |
| POST | 创建资源 | ❌ | ❌ |
| PUT | 完整更新 | ✅ | ❌ |
| PATCH | 部分更新 | ❌ | ❌ |
| DELETE | 删除资源 | ✅ | ❌ |
统一响应格式
成功响应
// 单个资源 { "success": true, "data": { "id": "123", "name": "张三", "email": "zhangsan@example.com" } } // 列表资源 { "success": true, "data": [ { "id": "1", "name": "用户1" }, { "id": "2", "name": "用户2" } ], "pagination": { "page": 1, "pageSize": 20, "total": 100, "totalPages": 5 } } // 创建成功 { "success": true, "data": { "id": "123", ... }, "message": "创建成功" }
错误响应
{ "success": false, "error": { "code": "VALIDATION_ERROR", "message": "请求参数无效", "details": [ { "field": "email", "message": "邮箱格式不正确" }, { "field": "age", "message": "年龄必须大于 0" } ] } }
API 路由实现
Next.js App Router
// app/api/users/route.ts import { NextRequest, NextResponse } from "next/server"; import { z } from "zod"; const CreateUserSchema = z.object({ name: z.string().min(1).max(100), email: z.string().email(), age: z.number().int().min(0).optional(), }); export async function GET(request: NextRequest) { try { const { searchParams } = new URL(request.url); const page = parseInt(searchParams.get("page") || "1"); const pageSize = parseInt(searchParams.get("pageSize") || "20"); const [users, total] = await Promise.all([ db.users.findMany({ skip: (page - 1) * pageSize, take: pageSize, }), db.users.count(), ]); return NextResponse.json({ success: true, data: users, pagination: { page, pageSize, total, totalPages: Math.ceil(total / pageSize), }, }); } catch (error) { return NextResponse.json( { success: false, error: { message: "获取用户失败" } }, { status: 500 }, ); } } export async function POST(request: NextRequest) { try { const body = await request.json(); const validated = CreateUserSchema.parse(body); const user = await db.users.create({ data: validated }); return NextResponse.json( { success: true, data: user, message: "创建成功" }, { status: 201 }, ); } catch (error) { if (error instanceof z.ZodError) { return NextResponse.json( { success: false, error: { code: "VALIDATION_ERROR", message: "请求参数无效", details: error.errors, }, }, { status: 400 }, ); } throw error; } }
FastAPI
# routers/users.py from fastapi import APIRouter, Query, HTTPException from pydantic import BaseModel, EmailStr router = APIRouter(prefix="/api/v1/users", tags=["users"]) class UserCreate(BaseModel): name: str email: EmailStr age: int | None = None class UserResponse(BaseModel): id: str name: str email: str @router.get("") async def list_users( page: int = Query(1, ge=1), page_size: int = Query(20, ge=1, le=100) ): skip = (page - 1) * page_size users = await db.users.find().skip(skip).limit(page_size).to_list() total = await db.users.count_documents({}) return { "success": True, "data": users, "pagination": { "page": page, "pageSize": page_size, "total": total, "totalPages": (total + page_size - 1) // page_size } } @router.post("", status_code=201) async def create_user(user: UserCreate): result = await db.users.insert_one(user.dict()) created = await db.users.find_one({"_id": result.inserted_id}) return { "success": True, "data": created, "message": "创建成功" } @router.get("/{user_id}") async def get_user(user_id: str): user = await db.users.find_one({"_id": user_id}) if not user: raise HTTPException(status_code=404, detail="用户未找到") return {"success": True, "data": user}
Express.js
// routes/users.ts import { Router } from "express"; import { body, query, validationResult } from "express-validator"; const router = Router(); router.get( "/", [ query("page").optional().isInt({ min: 1 }), query("pageSize").optional().isInt({ min: 1, max: 100 }), ], async (req, res, next) => { try { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ success: false, error: { code: "VALIDATION_ERROR", details: errors.array() }, }); } const page = parseInt(req.query.page as string) || 1; const pageSize = parseInt(req.query.pageSize as string) || 20; const [users, total] = await Promise.all([ User.find() .skip((page - 1) * pageSize) .limit(pageSize), User.countDocuments(), ]); res.json({ success: true, data: users, pagination: { page, pageSize, total, totalPages: Math.ceil(total / pageSize), }, }); } catch (error) { next(error); } }, ); router.post( "/", [body("name").notEmpty().isLength({ max: 100 }), body("email").isEmail()], async (req, res, next) => { try { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ success: false, error: { code: "VALIDATION_ERROR", details: errors.array() }, }); } const user = await User.create(req.body); res.status(201).json({ success: true, data: user, message: "创建成功" }); } catch (error) { next(error); } }, ); export default router;
查询参数处理
分页
interface PaginationParams { page?: number; pageSize?: number; cursor?: string; // 游标分页 } // 偏移分页 const { page = 1, pageSize = 20 } = query; const skip = (page - 1) * pageSize; // 游标分页(大数据量推荐) const { cursor, pageSize = 20 } = query; const where = cursor ? { id: { gt: cursor } } : {};
排序
// ?sort=createdAt:desc,name:asc const sortParam = query.sort as string; const orderBy = sortParam?.split(",").map((s) => { const [field, order] = s.split(":"); return { [field]: order || "asc" }; }) || [{ createdAt: "desc" }];
筛选
// ?status=active&role=admin const { status, role } = query; const where = { ...(status && { status }), ...(role && { role }), };
搜索
// ?q=keyword const { q } = query; const where = q ? { OR: [ { name: { contains: q, mode: "insensitive" } }, { email: { contains: q, mode: "insensitive" } }, ], } : {};
API 版本控制
URL 路径版本
/api/v1/users /api/v2/users
请求头版本
Accept: application/vnd.api+json; version=1
版本控制实现
// app/api/v1/users/route.ts export async function GET() { ... } // app/api/v2/users/route.ts export async function GET() { ... }
认证与授权
JWT 认证中间件
// middlewares/auth.ts import jwt from "jsonwebtoken"; export async function authMiddleware(request: NextRequest) { const token = request.headers.get("Authorization")?.replace("Bearer ", ""); if (!token) { return NextResponse.json( { success: false, error: { code: "UNAUTHORIZED", message: "未提供认证信息" }, }, { status: 401 }, ); } try { const decoded = jwt.verify(token, process.env.JWT_SECRET!); request.user = decoded; } catch (error) { return NextResponse.json( { success: false, error: { code: "UNAUTHORIZED", message: "Token 无效" }, }, { status: 401 }, ); } }
权限检查
export function requireRole(...roles: string[]) { return (request: NextRequest) => { if (!roles.includes(request.user.role)) { return NextResponse.json( { success: false, error: { code: "FORBIDDEN", message: "权限不足" } }, { status: 403 }, ); } }; } // 使用 export async function DELETE(request: NextRequest) { const authError = await authMiddleware(request); if (authError) return authError; const roleError = requireRole("admin")(request); if (roleError) return roleError; // 执行删除 }
HTTP 状态码
| 状态码 | 含义 | 使用场景 |
|---|---|---|
| 200 | OK | 成功获取/更新 |
| 201 | Created | 成功创建 |
| 204 | No Content | 成功删除 |
| 400 | Bad Request | 请求参数错误 |
| 401 | Unauthorized | 未认证 |
| 403 | Forbidden | 无权限 |
| 404 | Not Found | 资源不存在 |
| 409 | Conflict | 资源冲突 |
| 422 | Unprocessable Entity | 业务逻辑错误 |
| 429 | Too Many Requests | 请求过多 |
| 500 | Internal Server Error | 服务器错误 |
最佳实践
- 使用名词复数 -
而非/users/user - HTTP 方法语义 - GET 读取,POST 创建,PUT/PATCH 更新
- 统一响应格式 - success、data、error、pagination
- 输入验证 - 使用 Zod/Pydantic 验证
- 错误处理 - 返回有意义的错误码和消息
- 版本控制 - /api/v1/
- 分页 - 列表接口必须分页
- HATEOAS - 可选,返回相关链接
- 文档 - OpenAPI/Swagger 文档
- 幂等性 - PUT、DELETE 保持幂等