You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Node.js应用中实现API领域模型的最佳模式与技术

Node.js API客户端领域类实现与设计模式

要实现这种领域化的API客户端,核心是把API的每个资源(Products、Lists、Categories)封装成独立的语义化类,同时复用底层的HTTP请求逻辑,避免重复造轮子。下面是具体实现方案和适用的设计模式:

最佳实现步骤

1. 封装底层HTTP工具类

先写一个通用的HTTP客户端,处理认证、请求发送、错误捕获这些重复逻辑,让所有领域类共享这个工具,不用每个类都写一遍请求代码:

// 注意:Node.js 18+内置fetch,低于18版本需要安装node-fetch
class HttpClient {
  constructor(baseUrl, apiKey) {
    this.baseUrl = baseUrl;
    this.apiKey = apiKey;
  }

  async request(method, path, data = null) {
    const options = {
      method,
      headers: {
        'Authorization': `Bearer ${this.apiKey}`,
        'Content-Type': 'application/json'
      }
    };

    if (data) options.body = JSON.stringify(data);

    const response = await fetch(`${this.baseUrl}${path}`, options);
    if (!response.ok) {
      const errorDetails = await response.json().catch(() => ({ message: response.statusText }));
      throw new Error(`API请求失败: ${errorDetails.message || response.status}`);
    }

    return response.json();
  }
}

2. 实现领域资源类

每个领域类(比如Products)通过构造函数注入HttpClient,封装对应API的操作,对外暴露语义化的方法:

class Products {
  constructor(httpClient) {
    this.http = httpClient;
  }

  // 根据ID获取商品
  async getById(productId) {
    return this.http.request('GET', `/products/${productId}`);
  }

  // 创建新商品
  async create(productData) {
    return this.http.request('POST', '/products', productData);
  }

  // 分页/筛选商品列表
  async list(filter = {}) {
    const queryStr = new URLSearchParams(filter).toString();
    return this.http.request('GET', `/products?${queryStr}`);
  }
}

// 同理实现Categories类
class Categories {
  constructor(httpClient) {
    this.http = httpClient;
  }

  async getAll() {
    return this.http.request('GET', '/categories');
  }

  async getCategoryProducts(categoryId) {
    return this.http.request('GET', `/categories/${categoryId}/products`);
  }
}

3. 统一客户端入口

写一个总入口类,初始化HttpClient并创建所有领域类的实例,对外提供统一的访问入口,用户不用逐个实例化领域类:

class APIClient {
  constructor(config) {
    this.http = new HttpClient(config.baseUrl, config.apiKey);
    this.products = new Products(this.http);
    this.categories = new Categories(this.http);
    this.lists = new Lists(this.http); // 假设已实现Lists类
  }
}

// 使用示例
const client = new APIClient({
  baseUrl: 'https://api.example.com/v1',
  apiKey: 'your-api-token'
});

// 调用领域方法
const myProduct = await client.products.getById('123');
const allCategories = await client.categories.getAll();

适用的设计模式

1. 门面模式(Facade)

APIClient就是典型的门面——把多个领域类的操作收拢到一个入口,用户只需要初始化一次客户端,就能直接调用所有资源的方法,不用关心内部各个领域类的细节。

2. 依赖注入(Dependency Injection)

每个领域类通过构造函数接收HttpClient实例,这种方式让代码解耦:比如测试时可以替换成Mock版的HttpClient,不用修改领域类的代码;如果后续要更换HTTP库,只需要修改HttpClient实现即可。

3. 仓储模式(Repository Pattern)

领域类的设计符合仓储模式的思路:把对外部API的操作封装成类似数据仓储的语义化接口,上层代码不用关心API的具体路径、请求方式,只需要调用getById、list这种直观方法。

额外优化建议

  • 业务错误封装:在HttpClient或领域类里,可以把HTTP错误转换成更具体的业务错误(比如ProductNotFoundError),方便上层代码针对性处理。
  • 缓存逻辑:对于不经常更新的资源(比如分类列表),可以在领域类里加入内存缓存,减少重复请求。
  • 请求拦截:在HttpClient里添加请求/响应拦截器,方便统一添加日志、修改请求头、处理响应数据格式。

内容的提问来源于stack exchange,提问作者dbr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 17:55:15