使用 Claude Code 构建 RESTful API

中级 50分钟 更新时间: 2024年11月

🎯 RESTful API 基础

RESTful API 是现代Web应用的核心。使用 Claude Code,你可以:

  • 快速生成代码:自动生成路由、控制器、模型
  • 遵循最佳实践:代码符合REST规范和安全标准
  • 自动化文档:生成API文档和测试用例
  • 错误处理:完善的异常处理和错误响应

RESTful API 核心原则:

  • 资源导向:一切皆资源(用户、文章、商品等)
  • HTTP 方法:GET(获取)、POST(创建)、PUT(更新)、DELETE(删除)
  • 无状态:每个请求包含所有必要信息
  • 统一接口:一致的URL结构和响应格式

🛠️ 选择合适的框架

Python 框架对比

让 Claude 帮你选择框架:

你:我要开发一个用户管理API,应该选择哪个Python框架?

Claude 的建议:

1. **FastAPI** (推荐)
   优点:
   - 现代化、性能优异
   - 自动生成API文档(Swagger UI)
   - 类型提示和数据验证
   - 异步支持

   适用场景:新项目、高性能需求、需要自动文档

2. **Flask**
   优点:
   - 轻量级、灵活
   - 生态系统成熟
   - 学习曲线平缓

   适用场景:简单API、快速原型、完全控制

3. **Django REST Framework**
   优点:
   - 功能全面
   - 内置ORM和管理后台
   - 企业级特性

   适用场景:大型项目、需要管理后台、数据库操作多

本教程使用 FastAPI 演示

🚀 项目初始化

1. 让 Claude 创建项目结构

提示词:

你:帮我创建一个FastAPI项目结构,用于用户管理系统

Claude 生成:
project/
├── app/
│   ├── __init__.py
│   ├── main.py          # 应用入口
│   ├── models.py        # 数据模型
│   ├── schemas.py       # Pydantic模式
│   ├── crud.py          # 数据库操作
│   ├── database.py      # 数据库配置
│   └── routers/
│       ├── __init__.py
│       └── users.py     # 用户路由
├── tests/
│   ├── __init__.py
│   └── test_users.py
├── requirements.txt
├── .env
└── README.md

2. 安装依赖

requirements.txt:

fastapi==0.104.1
uvicorn[standard]==0.24.0
sqlalchemy==2.0.23
pydantic==2.5.0
python-jose[cryptography]==3.3.0
passlib[bcrypt]==1.7.4
python-multipart==0.0.6
pytest==7.4.3
httpx==0.25.2

📝 构建 API 端点

1. 定义数据模型

让 Claude 生成模型代码:

你:创建用户模型,包含ID、用户名、邮箱、密码哈希、创建时间

# models.py
from sqlalchemy import Column, Integer, String, DateTime
from sqlalchemy.sql import func
from .database import Base

class User(Base):
    __tablename__ = "users"

    id = Column(Integer, primary_key=True, index=True)
    username = Column(String, unique=True, index=True, nullable=False)
    email = Column(String, unique=True, index=True, nullable=False)
    hashed_password = Column(String, nullable=False)
    created_at = Column(DateTime(timezone=True), server_default=func.now())
    updated_at = Column(DateTime(timezone=True), onupdate=func.now())

2. 创建 Pydantic Schema

schemas.py:

from pydantic import BaseModel, EmailStr
from datetime import datetime
from typing import Optional

class UserBase(BaseModel):
    username: str
    email: EmailStr

class UserCreate(UserBase):
    password: str

class UserUpdate(BaseModel):
    username: Optional[str] = None
    email: Optional[EmailStr] = None
    password: Optional[str] = None

class UserResponse(UserBase):
    id: int
    created_at: datetime

    class Config:
        from_attributes = True

3. 实现 CRUD 操作

让 Claude 生成 CRUD 函数:

# crud.py
from sqlalchemy.orm import Session
from . import models, schemas
from passlib.context import CryptContext

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

def get_user(db: Session, user_id: int):
    return db.query(models.User).filter(models.User.id == user_id).first()

def get_user_by_email(db: Session, email: str):
    return db.query(models.User).filter(models.User.email == email).first()

def get_users(db: Session, skip: int = 0, limit: int = 100):
    return db.query(models.User).offset(skip).limit(limit).all()

def create_user(db: Session, user: schemas.UserCreate):
    hashed_password = pwd_context.hash(user.password)
    db_user = models.User(
        username=user.username,
        email=user.email,
        hashed_password=hashed_password
    )
    db.add(db_user)
    db.commit()
    db.refresh(db_user)
    return db_user

def update_user(db: Session, user_id: int, user: schemas.UserUpdate):
    db_user = get_user(db, user_id)
    if not db_user:
        return None

    update_data = user.model_dump(exclude_unset=True)
    if "password" in update_data:
        update_data["hashed_password"] = pwd_context.hash(update_data.pop("password"))

    for field, value in update_data.items():
        setattr(db_user, field, value)

    db.commit()
    db.refresh(db_user)
    return db_user

def delete_user(db: Session, user_id: int):
    db_user = get_user(db, user_id)
    if db_user:
        db.delete(db_user)
        db.commit()
        return True
    return False

4. 创建 API 路由

routers/users.py:

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from typing import List
from .. import crud, schemas
from ..database import get_db

router = APIRouter(prefix="/users", tags=["users"])

@router.post("/", response_model=schemas.UserResponse, status_code=status.HTTP_201_CREATED)
def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)):
    """创建新用户"""
    db_user = crud.get_user_by_email(db, email=user.email)
    if db_user:
        raise HTTPException(
            status_code=400,
            detail="Email already registered"
        )
    return crud.create_user(db=db, user=user)

@router.get("/", response_model=List[schemas.UserResponse])
def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
    """获取用户列表"""
    users = crud.get_users(db, skip=skip, limit=limit)
    return users

@router.get("/{user_id}", response_model=schemas.UserResponse)
def read_user(user_id: int, db: Session = Depends(get_db)):
    """获取单个用户"""
    db_user = crud.get_user(db, user_id=user_id)
    if db_user is None:
        raise HTTPException(status_code=404, detail="User not found")
    return db_user

@router.put("/{user_id}", response_model=schemas.UserResponse)
def update_user(user_id: int, user: schemas.UserUpdate, db: Session = Depends(get_db)):
    """更新用户信息"""
    db_user = crud.update_user(db, user_id=user_id, user=user)
    if db_user is None:
        raise HTTPException(status_code=404, detail="User not found")
    return db_user

@router.delete("/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_user(user_id: int, db: Session = Depends(get_db)):
    """删除用户"""
    success = crud.delete_user(db, user_id=user_id)
    if not success:
        raise HTTPException(status_code=404, detail="User not found")
    return None

🔐 身份验证

实现 JWT 认证

让 Claude 添加认证功能:

你:为API添加JWT认证

# auth.py
from datetime import datetime, timedelta
from jose import JWTError, jwt
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from sqlalchemy.orm import Session

SECRET_KEY = "your-secret-key-here"  # 应该从环境变量读取
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

def create_access_token(data: dict):
    to_encode = data.copy()
    expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

def get_current_user(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        user_id: int = payload.get("sub")
        if user_id is None:
            raise credentials_exception
    except JWTError:
        raise credentials_exception

    user = crud.get_user(db, user_id=user_id)
    if user is None:
        raise credentials_exception
    return user

🧪 API 测试

让 Claude 生成测试用例:

# tests/test_users.py
from fastapi.testclient import TestClient
from app.main import app

client = TestClient(app)

def test_create_user():
    response = client.post(
        "/users/",
        json={
            "username": "testuser",
            "email": "test@example.com",
            "password": "testpass123"
        }
    )
    assert response.status_code == 201
    data = response.json()
    assert data["username"] == "testuser"
    assert data["email"] == "test@example.com"
    assert "id" in data

def test_read_users():
    response = client.get("/users/")
    assert response.status_code == 200
    assert isinstance(response.json(), list)

def test_read_user():
    # 先创建用户
    create_response = client.post(
        "/users/",
        json={
            "username": "testuser2",
            "email": "test2@example.com",
            "password": "testpass123"
        }
    )
    user_id = create_response.json()["id"]

    # 读取用户
    response = client.get(f"/users/{user_id}")
    assert response.status_code == 200
    data = response.json()
    assert data["id"] == user_id

def test_user_not_found():
    response = client.get("/users/99999")
    assert response.status_code == 404

🚀 部署上线

部署选项:

  • Docker:容器化部署,一致的运行环境
  • 云平台:AWS, Azure, Google Cloud
  • Vercel/Railway:快速部署Python应用
  • 自建服务器:使用Nginx + Gunicorn/Uvicorn

Dockerfile 示例:

FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

🚀 下一步

继续深入学习: