Javascript 我应该选择代码重复还是使用api service-JS进行整合
我正在一个大型CMS系统上工作,其中一个特定模块及其子模块利用相同的后端API。除了“文档类型”之外,每个子模块的端点完全相同 因此,我们遵循这样一种模式: api/path/v1/{document type} api/path/v1/{document type}/{id} api/path/v1/{document type}/{id}/versions 随着时间的推移,使用此API的模块数量不断增加,我只剩下许多实现7种CRUD方法的冗余API服务:Javascript 我应该选择代码重复还是使用api service-JS进行整合,javascript,api,design-patterns,architecture,redundancy,Javascript,Api,Design Patterns,Architecture,Redundancy,我正在一个大型CMS系统上工作,其中一个特定模块及其子模块利用相同的后端API。除了“文档类型”之外,每个子模块的端点完全相同 因此,我们遵循这样一种模式: api/path/v1/{document type} api/path/v1/{document type}/{id} api/path/v1/{document type}/{id}/versions 随着时间的推移,使用此API的模块数量不断增加,我只剩下许多实现7种CRUD方法的冗余API服务: getAllXs() {...} g
getAllXs() {...}
getX(id) {...}
getXVersion(id, versionId) {...}
etc...
用一个像这样的单独方法
getAllXs() {
let endpoint = BASE.URL + ENDPOINTS.X;
let config = ...
return http.get(endpoint, config)
.then(response => response.data);
.catch(...);
}
其中X将是特定文档类型的名称
我到了一个地步,我决定做一个单一的服务,并做这样的事情:
const BASE_URL = window.config.baseUrl + Const.API_ENDPOINT;
const ENDPOINTS = {
"W": "/v1/W/",
"X": "/v1/X/",
"Y": "/v1/Y/",
"Z": "/v1/Z/",
}
getAllDocuments(docType, config={}) {
let endpoint = BASE_URL + ENDPOINTS[docType];
return http.get(endpoint, config)
.then(response => response.data);
.catch(...);
}
...other methods
其中指定了类型,并使用映射的端点来构建路径
这将所有文档api服务减少到一个。这在代码方面更加简洁,但显然现在需要一个额外的参数,术语也更加通用:
getAllXs()-->getAllDocuments()
而且它的“防白痴性”也少了一点。目前的编写方式让我感到不安全的是,有6个模块使用这个API,每个服务中有7个相同的方法
我一直在问自己的问题是:
- 我的动态功能是否接近反模式
- 如果我有10多个模块使用相同的API会怎么样
注:
getAllDocuments
的名称实际上比getAllDocType1s
要好,如果这是您原始代码中的真实名称。您的问题让我想到了一个常见的设计问题
当涉及到设计时,没有单一的真理来源,但是如果你在你正在构建的东西和价值中认识到ORM,我会给你一些灵感
这里是我在许多项目中使用过的普通ES6 ORM的过度简化(重用代码片段以提高可靠性)。这个设计的灵感来自于我在其他语言中使用的大量ORM框架
class ORM {
constructor() {
this.BASEURL = window.config.baseUrl + Const.API_ENDPOINT
this.config = {foo:bar} // default config
}
getAll() {
let endpoint = this.BASEURL + this.ENDPOINT
return http.get(endpoint, this.config)
.then(response => response.data)
.catch(...)
}
get(id) {
// ...
}
}
以及该类的扩展示例(请注意具有特殊配置的一个)
因为你是在问这是否是反模式。我建议你阅读一些关于设计、原则和总体设计的书籍。您还将发现有关全局常量的代码气味,但这只有在窗口上下文中才会出现。我发现您已经走上了正确的道路,试图避免出现以下情况::-)
祝你好运,请毫不犹豫地提出更多问题,并在评论中添加更多细节 虽然我分享了x00的大部分答案,但我会考虑端点的静态程度 是否有机会模块“X”可以更改其任何端点定义?例如,您需要再传递一个查询参数。您的模块是否完全相同,没有改变的余地 如果答案是否定的,那就开始吧。要进行简单的更改,您必须重构整个代码库(如果您按照您建议的方式实现它的话) 如果答案是肯定的,那么,我认为您没有理由不实施拟议的动态功能。就我个人而言,我倾向于我的模块扩展和使用的服务,以防我想对它们做最小的更改。例如:
类MyGenericService{
构造函数(){
this.url=window.config.baseUrl;
}
异步getAllDocuments(配置){
返回http.get(this.url,config)
.然后(response=>response.data);
.捕获(…);
};
//……等等
}
这使得我的代码可以扩展和修改,只需要一个外卖,即每个模块需要维护一个文件,它有如下内容:
const BASE_URL = window.config.baseUrl + Const.API_ENDPOINT;
const ENDPOINTS = {
"W": "/v1/W/",
"X": "/v1/X/",
"Y": "/v1/Y/",
"Z": "/v1/Z/",
}
getAllDocuments(docType, config={}) {
let endpoint = BASE_URL + ENDPOINTS[docType];
return http.get(endpoint, config)
.then(response => response.data);
.catch(...);
}
...other methods
classxservice扩展了MyGenericService{
构造函数(){
this.url=window.config.baseUrl+'/v1/x';
}
}
如果维护这些额外文件的开销太大,您可以在MyGenericService的构造函数中接收端点的URL,您只需要在控制器中执行以下操作:
constmyxservice=newmygenericservice('/v1/x');
const myYService=new MyGenericService('/v1/y');
//…或者它可以使用您的端点url映射
//我真的不知道你的代码是如何构造的,只是给你一些想法
你有一些选择,希望对你有所帮助 getAllResponses()将是一个实际的示例。。。虽然我尽可能地遵守DRY,但由于添加了额外的参数/标志以适应不断增长的需求,使函数变得过于动态,我受到了影响。这就是为什么我在这里(一个接口将是完美的解决方案)。我倾向于冗余的主要原因是,在某些情况下,特定的文档api服务可能需要额外的头或参数。