在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
相关产品推荐
相关产品推荐

