设计模式-编写API包装器库打字稿

问题描述

遇到一些问题,试图提出一种编码方法。首先,我要说这不是我的强项,也没有尝试过类似的方法

目标:为客户端创建包装API库。它应该公开一种使用basePath实例化lib的方法/类,然后公开其名称间的对象/类及其上的调用内部API的方法,因此,使用者只需传递每个API调用所需的数据即可。简单,因此我们通常可以处理诸如错误之类的事情。

我知道我在这里无法工作-但这主要是为了了解我希望达到的目标。

我的问题是类似的

  • 是否应该通过静态方法设置basePath,而basePath只是一个属性
  • 这又如何构成,以便我们可以共享方法和对basePath的访问,而不必每次都实例化它?

感谢所有帮助和建议。

abstract class Base { 
    constructor(private basePath: string = '') {}
    async get<T>(endpoint: string,config?: Requestinit | undefined): Promise<T> { 
        const response = await fetch(this.basePath + endpoint,config);
        return response.json();
    }
    // ... other methods that would be available  
}

// Exported to the consumer for ease of use. Others Could be `Comments.postNewComment({user,data})`
class Posts extends Base {
  getAllPosts() {
    return this.get<PostsData>('/posts')
  }
}

// In the main index file for lib,it would export all the classes with available API methods (such as Posts,Auth,Comments etc) that the consumer would be able to use.
// Issue comes up when creating an instance of these because it would require the basePath again
export { Posts: new Posts(),Comments: new Comments() }; 

// Ideal usage: Main file of the app:
import LibName from 'lib-name'
new LibName({ basePath: 'api.whatever' }) // Left out re: brevity,but would be the class where we instantiate the basePath,and anything else

// In other locations through the app,be able to call the varIoUs methods from different sections (Auth.login,Comments.addNewComment etc)
import { Posts } from 'lib-name';
Posts.getAllPosts();

我一开始就遵循this article,但这的最后一个示例在一个导出(DevToClient.X)下公开了所有方法,而我希望将它们命名为其相应的父对象的命名空间。

解决方法

为什么不为依赖于对象 Endpoint 的类型的 T 创建一个可实例化的类?

class Endpoint<T extends {id: string},Creatable = T> { 
    constructor(private endpointPath: string) {}
    async get(id: string,config?: RequestInit | undefined): Promise<T> { 
        const response = await fetch(this.endpointPath + '/' + id,config);
        return response.json();
    }
    // stubs of sample methods
    async getAll( someFilters?: any ): Promise<T[]> {}
    async update(changes: Partial<T> & {id: string}): Promise<T> {}
    async createNew( object: Creatable ): Promise<T> {}
}

我还添加了第二个可选参数 Creatable,因为创建请求不包含所创建对象的每个属性是正常的。例如,iddate 可能是由服务器设置的。

我们不会导出 Endpoint 类,而是会为不同类型创建实例并导出它们。

export const Posts = new Endpoint<PostObject>('/posts');
export const Comments = new Endpoint<Comments>('/comments');

你可以这样使用它:

import {Posts} from 'some-lib'

const post = Posts.get("321"); // Promise<PostObject>

// the arguments depend on your partuicular api structure
const latest = Posts.getAll({limit: 10,sort: 'date'}); // Promise<PostObject[]>

const updated = Posts.update({id: "123",title: "New Title"}); // Promise<PostObject>

如果您想支持更高级的配置,这些配置在端点之间有所不同,例如验证,这就是您可以使用组合的地方。 Endpoint 可以在构造函数中接受某种类型的 config 对象或类。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...