如何在函数式编程范例中动态调用 API

How to call an API dynamically in functional programming paradigm

我的应用程序接收来自 humain 客户端的 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 原则,我猜,因为如果要添加第 13 个 api,requestPrice.js 不会改变。 另一方面,我应该能够轻松地对文件 requestPrice.js 进行单元测试,因为 req 可以被注入。

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

我建议使用工厂方法(在 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等)都可以在自己单独的文件中,服务的调用者不需要知道调用哪个impl,因此保持了依赖倒置。高层模块不知道底层模块。 :)