首页 > 解决方案 > 如何在函数式编程范式中动态调用 API

问题描述

我的应用程序接收来自人类客户端的 http 请求。

我的应用程序只需要调用 12 个 API 中的一个 API,这取决于它接收到的输入中的一个特定数据。

我的第一个想法当然是

// requestPrice.js

const service = req.body.service

const APIs = {
    ser1: callAPI1,
    ser2: callAPI2,
    ser3: callAPI3,
    // ...
    ser12: callAPI12,
}

return APIs[service](req.body)

这工作正常,但我想需要一些重构以使其符合 SOLID。通常在 OOP 中,我可能会使用其中一种设计模式,例如策略或责任链。

但是我使用的函数式编程有点不同。

我想过做以下事情:

// ser1.js
export default callAPI(data) {
    // code 1
}

// ser2.js
export default callAPI(data) {
    // code 2
}

// ser3.js
export default callAPI(data) {
    // code 3
}

//...

// ser12.js
export default callAPI(data) {
    // code 12
}

// requestPrice.js
const service = req.body.service
const api = require(`./${service}`)

return api(req.body)

这看起来比第一个版本好得多,因为它更好地遵循单一责任原则。另外,我猜它也遵循 Open/Closed 原则,因为requestPrice.js如果要添加第 13 个 api,它不会改变。另一方面,我应该能够轻松地对文件进行单元测试,requestPrice.js因为req可以注入。

这样做是否符合 SOLID 原则,还是有更好更清洁的方法?

标签: javascriptnode.jsfunctional-programmingclean-architecture

解决方案


我建议使用工厂方法(在 FP 中实现为柯里化函数),以便决定调用哪个服务以及在每个服务中做什么是分开的。request.body 应该传递给返回的 impl 函数。

function createService(body) {
  if(checkInput(body) == [something]) return service1;
  else if(checkInput(body) == [something2]) return service2;
  ..
}

function service1(body) {..}
function service2(body) {..}
..

let service = createService(req.body);
service(request.body);

我没有把它放在不同的文件中,但你可以这样做。现在 createService 可以在不同的模块中。并且每个 impl(service1、service2 等)都可以在自己的单独文件中,并且 service 的调用者不需要知道要调用哪个 impl,从而保持依赖倒置。高级模块不知道低级模块。:)


推荐阅读