当前位置:首页 > 学习笔记 > 正文内容

API设计完全指南:RESTful与GraphQL最佳实践

API设计完全指南
"优秀的API设计是系统集成的基石。清晰的接口规范、合理的版本策略、完善的安全机制,让API易于理解、使用和维护。"

一、RESTful API设计原则

REST架构风格强调资源的表述和状态转移,核心原则包括: 资源为中心:URL表示资源,HTTP方法表示操作 无状态:每个请求包含所有必要信息 统一接口:遵循一致的约定

URL设计规范

# 使用名词表示资源,使用复数形式
GET    /users              # 获取用户列表
POST   /users              # 创建新用户
GET    /users/{id}         # 获取指定用户
PUT    /users/{id}         # 更新指定用户(完整替换)
PATCH  /users/{id}         # 部分更新用户
DELETE /users/{id}         # 删除用户

# 资源嵌套表示关系
GET    /users/{id}/orders  # 获取用户的订单
POST   /users/{id}/orders  # 为用户创建订单

# 使用查询参数过滤和分页
GET    /users?role=admin&sort=-created_at
GET    /users?page=2&limit=20

HTTP状态码使用

200 OK          # 成功处理请求
201 Created     # 成功创建资源
204 No Content  # 成功但无返回内容(删除操作)

400 Bad Request      # 请求参数错误
401 Unauthorized     # 未认证
403 Forbidden        # 无权限
404 Not Found        # 资源不存在
409 Conflict         # 资源冲突

500 Internal Server Error  # 服务器错误
503 Service Unavailable    # 服务不可用

二、API响应格式

统一响应结构

{
  "code": 0,
  "message": "success",
  "data": {
    "users": [...],
    "pagination": {
      "page": 1,
      "limit": 20,
      "total": 100,
      "totalPages": 5
    }
  }
}

// 错误响应
{
  "code": 40001,
  "message": "用户名已存在",
  "errors": [
    {
      "field": "username",
      "message": "该用户名已被注册"
    }
  ]
}

三、API版本管理

# URL路径版本(推荐)
/api/v1/users
/api/v2/users

# HTTP头部版本
Accept: application/vnd.myapi.v1+json

# 查询参数版本
/api/users?version=1

四、GraphQL实践

Schema定义

type User {
  id: ID!
  username: String!
  email: String!
  role: Role!
  orders: [Order!]!
  createdAt: DateTime!
}

type Order {
  id: ID!
  user: User!
  items: [OrderItem!]!
  total: Float!
  status: OrderStatus!
}

enum Role {
  ADMIN
  USER
  GUEST
}

type Query {
  user(id: ID!): User
  users(filter: UserFilter, page: Int, limit: Int): UserConnection!
}

type Mutation {
  createUser(input: CreateUserInput!): User!
  updateUser(id: ID!, input: UpdateUserInput!): User!
  deleteUser(id: ID!): Boolean!
}

input CreateUserInput {
  username: String!
  email: String!
  password: String!
}

解析器实现

const resolvers = {
  Query: {
    user: async (_, { id }, { dataSources }) => {
      return dataSources.userAPI.getUserById(id);
    },
    
    users: async (_, { filter, page = 1, limit = 20 }, { dataSources }) => {
      const { users, total } = await dataSources.userAPI.getUsers(filter, page, limit);
      return {
        data: users,
        pagination: {
          page,
          limit,
          total,
          totalPages: Math.ceil(total / limit)
        }
      };
    }
  },
  
  User: {
    orders: async (user, _, { dataSources }) => {
      return dataSources.orderAPI.getOrdersByUserId(user.id);
    }
  },
  
  Mutation: {
    createUser: async (_, { input }, { dataSources }) => {
      const user = await dataSources.userAPI.createUser(input);
      return user;
    }
  }
};

五、API安全实践

认证机制

// JWT认证中间件
const authMiddleware = (req, res, next) => {
  const token = req.headers.authorization?.split(' ')[1];
  
  if (!token) {
    return res.status(401).json({ message: '未提供认证令牌' });
  }
  
  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    req.user = decoded;
    next();
  } catch (error) {
    return res.status(401).json({ message: '令牌无效或已过期' });
  }
};

// OAuth2.0授权码流程
const oauthCallback = async (code) => {
  const response = await fetch('https://oauth.provider.com/token', {
    method: 'POST',
    body: new URLSearchParams({
      grant_type: 'authorization_code',
      code,
      client_id: process.env.CLIENT_ID,
      client_secret: process.env.CLIENT_SECRET,
      redirect_uri: process.env.REDIRECT_URI
    })
  });
  
  const { access_token, refresh_token } = await response.json();
  return { accessToken: access_token, refreshToken: refresh_token };
};

限流与防护

// 限流中间件
const rateLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,  // 15分钟
  max: 100,  // 最多100次请求
  message: {
    code: 42901,
    message: '请求过于频繁,请稍后再试'
  },
  keyGenerator: (req) => {
    return req.user?.id || req.ip;
  }
});

app.use('/api', rateLimiter);

// 参数验证
const validateUser = celebrate({
  body: Joi.object({
    username: Joi.string().alphanum().min(3).max(30).required(),
    email: Joi.string().email().required(),
    password: Joi.string().pattern(new RegExp('^[a-zA-Z0-9]{8,30}$')).required()
  })
});

app.post('/api/v1/users', validateUser, createUser);

六、API文档

OpenAPI规范

openapi: 3.0.3
info:
  title: My API
  version: 1.0.0

paths:
  /users:
    get:
      summary: 获取用户列表
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserList'
    
    post:
      summary: 创建用户
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateUser'
      responses:
        '201':
          description: 创建成功

components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: integer
        username:
          type: string
        email:
          type: string

总结

优秀的API设计需要遵循一致的规范,提供清晰的文档,并确保安全性。RESTful适合简单的CRUD场景,GraphQL适合复杂数据查询。无论选择哪种方式,都要注重开发者体验,让API易于理解和使用。

本文链接:https://www.kkkliao.cn/?id=853 转载需授权!

分享到:

版权声明:本文由廖万里的博客发布,如需转载请注明出处。


发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。