Skip to content

API 和集成

概述

Node.js 在构建 API 和集成外部服务方面表现出色。本章涵盖 REST API 开发、GraphQL 实现、第三方服务集成、身份验证以及 API 设计和使用的最佳实践。

REST API 开发

使用 Express 的基础 REST API

javascript
// rest-api-basic.js
const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');

const app = express();

// 安全和中间件
app.use(helmet());
app.use(cors());
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));

// 速率限制
const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 分钟
  max: 100, // 每个 IP 在 windowMs 内限制 100 个请求
  message: {
    error: '此 IP 请求过多',
    retryAfter: '15 分钟'
  }
});
app.use('/api/', limiter);

// 模拟数据库
let users = [
  { id: 1, name: 'John Doe', email: 'john@example.com', createdAt: new Date() },
  { id: 2, name: 'Jane Smith', email: 'jane@example.com', createdAt: new Date() }
];
let nextId = 3;

// 验证中间件
const validateUser = (req, res, next) => {
  const { name, email } = req.body;
  const errors = [];

  if (!name || typeof name !== 'string' || name.trim().length === 0) {
    errors.push('名称是必需的,必须是非空字符串');
  }

  if (!email || typeof email !== 'string' || !email.includes('@')) {
    errors.push('需要有效的电子邮件地址');
  }

  if (errors.length > 0) {
    return res.status(400).json({
      success: false,
      message: '验证失败',
      errors
    });
  }

  next();
};

// GET /api/users - 获取所有用户(带分页)
app.get('/api/users', (req, res) => {
  const { page = 1, limit = 10, search, sortBy = 'id', sortOrder = 'asc' } = req.query;
  
  let filteredUsers = [...users];
  
  // 搜索功能
  if (search) {
    const searchLower = search.toLowerCase();
    filteredUsers = users.filter(user => 
      user.name.toLowerCase().includes(searchLower) ||
      user.email.toLowerCase().includes(searchLower)
    );
  }
  
  // 排序
  filteredUsers.sort((a, b) => {
    const aValue = a[sortBy];
    const bValue = b[sortBy];
    
    if (sortOrder === 'desc') {
      return aValue < bValue ? 1 : -1;
    }
    return aValue > bValue ? 1 : -1;
  });
  
  // 分页
  const startIndex = (page - 1) * limit;
  const endIndex = startIndex + parseInt(limit);
  const paginatedUsers = filteredUsers.slice(startIndex, endIndex);
  
  res.json({
    success: true,
    data: paginatedUsers,
    pagination: {
      page: parseInt(page),
      limit: parseInt(limit),
      total: filteredUsers.length,
      pages: Math.ceil(filteredUsers.length / limit),
      hasNext: endIndex < filteredUsers.length,
      hasPrev: page > 1
    }
  });
});

// GET /api/users/:id - 根据 ID 获取用户
app.get('/api/users/:id', (req, res) => {
  const id = parseInt(req.params.id);
  const user = users.find(u => u.id === id);
  
  if (!user) {
    return res.status(404).json({
      success: false,
      message: '用户未找到'
    });
  }
  
  res.json({
    success: true,
    data: user
  });
});

// POST /api/users - 创建新用户
app.post('/api/users', validateUser, (req, res) => {
  const { name, email } = req.body;
  
  // 检查重复的电子邮件
  const existingUser = users.find(u => u.email === email);
  if (existingUser) {
    return res.status(409).json({
      success: false,
      message: '使用此电子邮件的用户已存在'
    });
  }
  
  const newUser = {
    id: nextId++,
    name: name.trim(),
    email: email.trim().toLowerCase(),
    createdAt: new Date(),
    updatedAt: new Date()
  };
  
  users.push(newUser);
  
  res.status(201).json({
    success: true,
    message: '用户创建成功',
    data: newUser
  });
});

// PUT /api/users/:id - 更新用户
app.put('/api/users/:id', validateUser, (req, res) => {
  const id = parseInt(req.params.id);
  const userIndex = users.findIndex(u => u.id === id);
  
  if (userIndex === -1) {
    return res.status(404).json({
      success: false,
      message: '用户未找到'
    });
  }
  
  const { name, email } = req.body;
  
  // 检查重复的电子邮件(排除当前用户)
  const existingUser = users.find(u => u.email === email && u.id !== id);
  if (existingUser) {
    return res.status(409).json({
      success: false,
      message: '另一个使用此电子邮件的用户已存在'
    });
  }
  
  users[userIndex] = {
    ...users[userIndex],
    name: name.trim(),
    email: email.trim().toLowerCase(),
    updatedAt: new Date()
  };
  
  res.json({
    success: true,
    message: '用户更新成功',
    data: users[userIndex]
  });
});

// DELETE /api/users/:id - 删除用户
app.delete('/api/users/:id', (req, res) => {
  const id = parseInt(req.params.id);
  const userIndex = users.findIndex(u => u.id === id);
  
  if (userIndex === -1) {
    return res.status(404).json({
      success: false,
      message: '用户未找到'
    });
  }
  
  const deletedUser = users.splice(userIndex, 1)[0];
  
  res.json({
    success: true,
    message: '用户删除成功',
    data: deletedUser
  });
});

// 健康检查端点
app.get('/health', (req, res) => {
  res.json({
    status: 'healthy',
    timestamp: new Date().toISOString(),
    uptime: process.uptime(),
    memory: process.memoryUsage()
  });
});

// 404 处理器
app.use('*', (req, res) => {
  res.status(404).json({
    success: false,
    message: '端点未找到',
    path: req.originalUrl
  });
});

// 错误处理器
app.use((error, req, res, next) => {
  console.error('API Error:', error);
  
  res.status(error.status || 500).json({
    success: false,
    message: error.message || '内部服务器错误',
    ...(process.env.NODE_ENV === 'development' && { stack: error.stack })
  });
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`REST API 服务器运行在 http://localhost:${PORT}`);
});

高级 REST API 功能

javascript
// rest-api-advanced.js
const express = require('express');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
const multer = require('multer');
const path = require('path');

const app = express();
app.use(express.json());

// JWT 身份验证中间件
const authenticateToken = (req, res, next) => {
  const authHeader = req.headers['authorization'];
  const token = authHeader && authHeader.split(' ')[1];

  if (!token) {
    return res.status(401).json({ error: '需要访问令牌' });
  }

  jwt.verify(token, process.env.JWT_SECRET || 'secret', (err, user) => {
    if (err) {
      return res.status(403).json({ error: '无效或过期的令牌' });
    }
    req.user = user;
    next();
  });
};

// 基于角色的授权
const authorize = (roles = []) => {
  return (req, res, next) => {
    if (!req.user) {
      return res.status(401).json({ error: '需要身份验证' });
    }

    if (roles.length && !roles.includes(req.user.role)) {
      return res.status(403).json({ error: '权限不足' });
    }

    next();
  };
};

// 文件上传配置
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, 'uploads/');
  },
  filename: (req, file, cb) => {
    const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
    cb(null, file.fieldname + '-' + uniqueSuffix + path.extname(file.originalname));
  }
});

const upload = multer({
  storage,
  limits: {
    fileSize: 5 * 1024 * 1024 // 5MB 限制
  },
  fileFilter: (req, file, cb) => {
    const allowedTypes = /jpeg|jpg|png|gif|pdf/;
    const extname = allowedTypes.test(path.extname(file.originalname).toLowerCase());
    const mimetype = allowedTypes.test(file.mimetype);

    if (mimetype && extname) {
      return cb(null, true);
    } else {
      cb(new Error('无效的文件类型'));
    }
  }
});

// API 版本控制
const v1Router = express.Router();
const v2Router = express.Router();

// 版本 1 端点
v1Router.get('/users', (req, res) => {
  res.json({
    version: 'v1',
    users: [{ id: 1, name: 'John' }]
  });
});

// 版本 2 端点(增强的响应格式)
v2Router.get('/users', (req, res) => {
  res.json({
    version: 'v2',
    data: {
      users: [{ 
        id: 1, 
        firstName: 'John', 
        lastName: 'Doe',
        profile: { email: 'john@example.com' }
      }],
      meta: {
        total: 1,
        page: 1,
        limit: 10
      }
    }
  });
});

app.use('/api/v1', v1Router);
app.use('/api/v2', v2Router);

// 内容协商
app.get('/api/data', (req, res) => {
  const data = { message: 'Hello World', timestamp: new Date() };
  
  res.format({
    'application/json': () => {
      res.json(data);
    },
    'application/xml': () => {
      const xml = `<?xml version="1.0"?>
        <response>
          <message>${data.message}</message>
          <timestamp>${data.timestamp}</timestamp>
        </response>`;
      res.type('application/xml').send(xml);
    },
    'text/plain': () => {
      res.send(`${data.message} - ${data.timestamp}`);
    },
    default: () => {
      res.status(406).json({ error: '不可接受' });
    }
  });
});

// 文件上传端点
app.post('/api/upload', authenticateToken, upload.single('file'), (req, res) => {
  if (!req.file) {
    return res.status(400).json({ error: '未上传文件' });
  }

  res.json({
    success: true,
    message: '文件上传成功',
    file: {
      filename: req.file.filename,
      originalName: req.file.originalname,
      size: req.file.size,
      mimetype: req.file.mimetype,
      path: req.file.path
    }
  });
});

// 批量操作
app.post('/api/users/batch', authenticateToken, authorize(['admin']), (req, res) => {
  const { operations } = req.body;
  
  if (!Array.isArray(operations)) {
    return res.status(400).json({ error: '操作必须是数组' });
  }

  const results = operations.map((operation, index) => {
    try {
      switch (operation.type) {
        case 'create':
          return { index, success: true, data: { id: Date.now() + index, ...operation.data } };
        case 'update':
          return { index, success: true, data: { id: operation.id, ...operation.data } };
        case 'delete':
          return { index, success: true, message: `用户 ${operation.id} 已删除` };
        default:
          return { index, success: false, error: '未知的操作类型' };
      }
    } catch (error) {
      return { index, success: false, error: error.message };
    }
  });

  res.json({
    success: true,
    results,
    summary: {
      total: operations.length,
      successful: results.filter(r => r.success).length,
      failed: results.filter(r => !r.success).length
    }
  });
});

// 服务器发送事件 (SSE)
app.get('/api/events', (req, res) => {
  res.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive',
    'Access-Control-Allow-Origin': '*'
  });

  // 发送初始事件
  res.write(`data: ${JSON.stringify({ type: 'connected', timestamp: new Date() })}\n\n`);

  // 发送定期更新
  const interval = setInterval(() => {
    const event = {
      type: 'update',
      data: { value: Math.random(), timestamp: new Date() }
    };
    res.write(`data: ${JSON.stringify(event)}\n\n`);
  }, 5000);

  // 客户端断开连接时清理
  req.on('close', () => {
    clearInterval(interval);
    res.end();
  });
});

app.listen(3000);

GraphQL 实现

基础 GraphQL 服务器

javascript
// graphql-server.js
const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { buildSchema } = require('graphql');

// GraphQL 模式
const schema = buildSchema(`
  type User {
    id: ID!
    name: String!
    email: String!
    posts: [Post!]!
    createdAt: String!
  }

  type Post {
    id: ID!
    title: String!
    content: String!
    author: User!
    published: Boolean!
    createdAt: String!
  }

  input UserInput {
    name: String!
    email: String!
  }

  input PostInput {
    title: String!
    content: String!
    authorId: ID!
    published: Boolean = false
  }

  type Query {
    users: [User!]!
    user(id: ID!): User
    posts: [Post!]!
    post(id: ID!): Post
    searchUsers(query: String!): [User!]!
  }

  type Mutation {
    createUser(input: UserInput!): User!
    updateUser(id: ID!, input: UserInput!): User!
    deleteUser(id: ID!): Boolean!
    createPost(input: PostInput!): Post!
    updatePost(id: ID!, input: PostInput!): Post!
    deletePost(id: ID!): Boolean!
  }

  type Subscription {
    userAdded: User!
    postAdded: Post!
  }
`);

// 模拟数据
let users = [
  { id: '1', name: 'John Doe', email: 'john@example.com', createdAt: new Date().toISOString() },
  { id: '2', name: 'Jane Smith', email: 'jane@example.com', createdAt: new Date().toISOString() }
];

let posts = [
  { id: '1', title: 'First Post', content: 'Hello World', authorId: '1', published: true, createdAt: new Date().toISOString() },
  { id: '2', title: 'Second Post', content: 'GraphQL is awesome', authorId: '2', published: false, createdAt: new Date().toISOString() }
];

let nextUserId = 3;
let nextPostId = 3;

// 解析器
const root = {
  // 查询
  users: () => users,
  user: ({ id }) => users.find(user => user.id === id),
  posts: () => posts.map(post => ({
    ...post,
    author: users.find(user => user.id === post.authorId)
  })),
  post: ({ id }) => {
    const post = posts.find(post => post.id === id);
    if (post) {
      return {
        ...post,
        author: users.find(user => user.id === post.authorId)
      };
    }
    return null;
  },
  searchUsers: ({ query }) => {
    const searchTerm = query.toLowerCase();
    return users.filter(user => 
      user.name.toLowerCase().includes(searchTerm) ||
      user.email.toLowerCase().includes(searchTerm)
    );
  },

  // 变更
  createUser: ({ input }) => {
    const newUser = {
      id: String(nextUserId++),
      name: input.name,
      email: input.email,
      createdAt: new Date().toISOString()
    };
    users.push(newUser);
    return newUser;
  },

  updateUser: ({ id, input }) => {
    const userIndex = users.findIndex(user => user.id === id);
    if (userIndex === -1) {
      throw new Error('User not found');
    }
    
    users[userIndex] = {
      ...users[userIndex],
      ...input
    };
    
    return users[userIndex];
  },

  deleteUser: ({ id }) => {
    const userIndex = users.findIndex(user => user.id === id);
    if (userIndex === -1) {
      return false;
    }
    
    users.splice(userIndex, 1);
    // 同时删除用户的帖子
    posts = posts.filter(post => post.authorId !== id);
    return true;
  },

  createPost: ({ input }) => {
    const author = users.find(user => user.id === input.authorId);
    if (!author) {
      throw new Error('Author not found');
    }

    const newPost = {
      id: String(nextPostId++),
      title: input.title,
      content: input.content,
      authorId: input.authorId,
      published: input.published,
      createdAt: new Date().toISOString()
    };
    
    posts.push(newPost);
    
    return {
      ...newPost,
      author
    };
  },

  updatePost: ({ id, input }) => {
    const postIndex = posts.findIndex(post => post.id === id);
    if (postIndex === -1) {
      throw new Error('Post not found');
    }
    
    posts[postIndex] = {
      ...posts[postIndex],
      ...input
    };
    
    const author = users.find(user => user.id === posts[postIndex].authorId);
    
    return {
      ...posts[postIndex],
      author
    };
  },

  deletePost: ({ id }) => {
    const postIndex = posts.findIndex(post => post.id === id);
    if (postIndex === -1) {
      return false;
    }
    
    posts.splice(postIndex, 1);
    return true;
  }
};

// 向 User 类型添加 posts 字段
const originalUserResolver = root.user;
root.user = ({ id }) => {
  const user = users.find(user => user.id === id);
  if (user) {
    return {
      ...user,
      posts: posts.filter(post => post.authorId === id).map(post => ({
        ...post,
        author: user
      }))
    };
  }
  return null;
};

const app = express();

app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: root,
  graphiql: true, // 启用 GraphiQL 界面
}));

app.listen(4000, () => {
  console.log('GraphQL 服务器运行在 http://localhost:4000/graphql');
});

第三方 API 集成

HTTP 客户端封装

javascript
// api-client.js
const axios = require('axios');

class APIClient {
  constructor(baseURL, options = {}) {
    this.client = axios.create({
      baseURL,
      timeout: options.timeout || 10000,
      headers: {
        'Content-Type': 'application/json',
        ...options.headers
      }
    });

    this.retryConfig = {
      retries: options.retries || 3,
      retryDelay: options.retryDelay || 1000,
      retryCondition: options.retryCondition || this.defaultRetryCondition
    };

    this.setupInterceptors();
  }

  setupInterceptors() {
    // 请求拦截器
    this.client.interceptors.request.use(
      (config) => {
        console.log(`正在发送 ${config.method.toUpperCase()} 请求到 ${config.url}`);
        return config;
      },
      (error) => {
        console.error('请求错误:', error);
        return Promise.reject(error);
      }
    );

    // 响应拦截器
    this.client.interceptors.response.use(
      (response) => {
        console.log(`收到响应: ${response.status} ${response.statusText}`);
        return response;
      },
      async (error) => {
        const originalRequest = error.config;

        if (this.shouldRetry(error) && !originalRequest._retry) {
          originalRequest._retry = true;
          originalRequest._retryCount = (originalRequest._retryCount || 0) + 1;

          if (originalRequest._retryCount <= this.retryConfig.retries) {
            console.log(`重试请求 (${originalRequest._retryCount}/${this.retryConfig.retries})`);
            
            await this.delay(this.retryConfig.retryDelay * originalRequest._retryCount);
            return this.client(originalRequest);
          }
        }

        return Promise.reject(error);
      }
    );
  }

  defaultRetryCondition(error) {
    return (
      error.code === 'ECONNABORTED' ||
      error.code === 'ENOTFOUND' ||
      error.code === 'ECONNRESET' ||
      (error.response && error.response.status >= 500)
    );
  }

  shouldRetry(error) {
    return this.retryConfig.retryCondition(error);
  }

  delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  // 身份验证方法
  setAuthToken(token) {
    this.client.defaults.headers.common['Authorization'] = `Bearer ${token}`;
  }

  setApiKey(key, headerName = 'X-API-Key') {
    this.client.defaults.headers.common[headerName] = key;
  }

  // HTTP 方法
  async get(url, config = {}) {
    try {
      const response = await this.client.get(url, config);
      return response.data;
    } catch (error) {
      throw this.handleError(error);
    }
  }

  async post(url, data, config = {}) {
    try {
      const response = await this.client.post(url, data, config);
      return response.data;
    } catch (error) {
      throw this.handleError(error);
    }
  }

  async put(url, data, config = {}) {
    try {
      const response = await this.client.put(url, data, config);
      return response.data;
    } catch (error) {
      throw this.handleError(error);
    }
  }

  async delete(url, config = {}) {
    try {
      const response = await this.client.delete(url, config);
      return response.data;
    } catch (error) {
      throw this.handleError(error);
    }
  }

  handleError(error) {
    if (error.response) {
      // 服务器返回了错误状态
      const apiError = new Error(error.response.data?.message || error.message);
      apiError.status = error.response.status;
      apiError.data = error.response.data;
      return apiError;
    } else if (error.request) {
      // 已发出请求但未收到响应
      const networkError = new Error('网络错误: 未收到响应');
      networkError.code = 'NETWORK_ERROR';
      return networkError;
    } else {
      // 发生了其他情况
      return error;
    }
  }
}

// 特定服务的 API 客户端
class GitHubAPI extends APIClient {
  constructor(token) {
    super('https://api.github.com', {
      headers: {
        'Authorization': `token ${token}`,
        'Accept': 'application/vnd.github.v3+json'
      }
    });
  }

  async getUser(username) {
    return this.get(`/users/${username}`);
  }

  async getUserRepos(username) {
    return this.get(`/users/${username}/repos`);
  }

  async createRepo(data) {
    return this.post('/user/repos', data);
  }
}

class StripeAPI extends APIClient {
  constructor(secretKey) {
    super('https://api.stripe.com/v1', {
      headers: {
        'Authorization': `Bearer ${secretKey}`
      }
    });
  }

  async createCustomer(data) {
    return this.post('/customers', data);
  }

  async createPaymentIntent(data) {
    return this.post('/payment_intents', data);
  }

  async getCustomer(customerId) {
    return this.get(`/customers/${customerId}`);
  }
}

// 使用示例
async function demonstrateAPIIntegration() {
  // GitHub API 示例
  const github = new GitHubAPI(process.env.GITHUB_TOKEN);
  
  try {
    const user = await github.getUser('octocat');
    console.log('GitHub 用户:', user.name);
    
    const repos = await github.getUserRepos('octocat');
    console.log('仓库数量:', repos.length);
  } catch (error) {
    console.error('GitHub API 错误:', error.message);
  }

  // 通用 API 客户端示例
  const jsonPlaceholder = new APIClient('https://jsonplaceholder.typicode.com');
  
  try {
    const posts = await jsonPlaceholder.get('/posts');
    console.log('帖子数量:', posts.length);
    
    const newPost = await jsonPlaceholder.post('/posts', {
      title: '测试帖子',
      body: '这是一个测试帖子',
      userId: 1
    });
    console.log('创建的帖子:', newPost.id);
  } catch (error) {
    console.error('JSONPlaceholder API 错误:', error.message);
  }
}

module.exports = { APIClient, GitHubAPI, StripeAPI };

Webhook 处理

javascript
// webhook-handler.js
const express = require('express');
const crypto = require('crypto');
const bodyParser = require('body-parser');

class WebhookHandler {
  constructor() {
    this.handlers = new Map();
    this.middleware = [];
  }

  // 注册 webhook 处理器
  register(event, handler) {
    if (!this.handlers.has(event)) {
      this.handlers.set(event, []);
    }
    this.handlers.get(event).push(handler);
  }

  // 添加中间件
  use(middleware) {
    this.middleware.push(middleware);
  }

  // 验证 webhook 签名
  verifySignature(payload, signature, secret, algorithm = 'sha256') {
    const expectedSignature = crypto
      .createHmac(algorithm, secret)
      .update(payload)
      .digest('hex');
    
    return crypto.timingSafeEqual(
      Buffer.from(signature),
      Buffer.from(expectedSignature)
    );
  }

  // 处理 webhook
  async process(event, payload, headers = {}) {
    // 运行中间件
    for (const middleware of this.middleware) {
      await middleware(event, payload, headers);
    }

    // 获取事件处理器
    const handlers = this.handlers.get(event) || [];
    
    // 执行所有处理器
    const results = await Promise.allSettled(
      handlers.map(handler => handler(payload, headers))
    );

    // 记录任何失败
    results.forEach((result, index) => {
      if (result.status === 'rejected') {
        console.error(`事件 ${event} 的处理器 ${index} 失败:`, result.reason);
      }
    });

    return results;
  }

  // 创建 Express 中间件
  createExpressHandler(options = {}) {
    const {
      path = '/webhook',
      secret,
      signatureHeader = 'x-signature',
      eventHeader = 'x-event-type'
    } = options;

    const router = express.Router();

    // 用于签名验证的原始 body 解析器
    router.use(path, bodyParser.raw({ type: 'application/json' }));

    router.post(path, async (req, res) => {
      try {
        const payload = req.body;
        const signature = req.headers[signatureHeader];
        const event = req.headers[eventHeader];

        if (!event) {
          return res.status(400).json({ error: '缺少事件类型头' });
        }

        // 如果提供了密钥,则验证签名
        if (secret && signature) {
          if (!this.verifySignature(payload, signature, secret)) {
            return res.status(401).json({ error: '无效的签名' });
          }
        }

        // 解析 JSON 负载
        const parsedPayload = JSON.parse(payload.toString());

        // 处理 webhook
        await this.process(event, parsedPayload, req.headers);

        res.status(200).json({ success: true, message: 'Webhook 已处理' });
      } catch (error) {
        console.error('Webhook 处理错误:', error);
        res.status(500).json({ error: 'Webhook 处理失败' });
      }
    });

    return router;
  }
}

// 使用示例
const webhookHandler = new WebhookHandler();

// 添加日志中间件
webhookHandler.use(async (event, payload, headers) => {
  console.log(`收到 webhook: ${event}`, {
    timestamp: new Date().toISOString(),
    payloadSize: JSON.stringify(payload).length,
    userAgent: headers['user-agent']
  });
});

// 注册事件处理器
webhookHandler.register('user.created', async (payload) => {
  console.log('新用户已创建:', payload.user.email);
  // 发送欢迎邮件
  // 更新分析数据
});

webhookHandler.register('payment.completed', async (payload) => {
  console.log('支付已完成:', payload.payment.id);
  // 更新订单状态
  // 发送确认邮件
});

webhookHandler.register('order.shipped', async (payload) => {
  console.log('订单已发货:', payload.order.id);
  // 发送跟踪信息
  // 更新库存
});

// 创建 Express 应用
const app = express();

// 挂载 webhook 处理器
app.use(webhookHandler.createExpressHandler({
  path: '/webhooks',
  secret: process.env.WEBHOOK_SECRET,
  signatureHeader: 'x-hub-signature-256',
  eventHeader: 'x-github-event'
}));

app.listen(3000, () => {
  console.log('Webhook 服务器运行在 http://localhost:3000');
});

module.exports = WebhookHandler;

下一步

在下一章中,我们将探讨错误处理策略和构建健壮的 Node.js 应用程序的最佳实践。

练习

  1. 构建一个包含身份验证、授权和文件上传的完整 REST API
  2. 使用 WebSockets 创建一个带有订阅功能的 GraphQL API
  3. 实现一个用于处理 GitHub 事件的 webhook 系统
  4. 构建一个聚合多个微服务的 API 网关

要点

  • REST API 提供了一种标准化的方式来暴露应用程序功能
  • GraphQL 提供灵活的数据查询和实时订阅
  • 适当的身份验证和授权对 API 安全至关重要
  • HTTP 客户端封装简化了第三方 API 集成
  • Webhook 处理器支持实时事件处理
  • API 版本控制确保向后兼容性
  • 速率限制和验证防止滥用
  • 全面的错误处理提高了 API 可靠性

本站内容仅供学习和研究使用。