在几乎所有的应用程序中都有一个将所有应用的端点都抛出的文件。如果你正在使用Angular,它可能看起来像这样:
export const API = new InjectionToken('API');
const API_URL = `${environment.BASE_URL}/api/v1`;
export const endpoints = {
login: '${API_URL}/auth/login',
signup: '${API_URL}/auth/signup',
createTodo: '${API_URL}/todos/create',
updateTodo: '${API_URL}/todos/:id/update',
deleteTodo: '${API_URL}/todos/:id/delete,
.....
};
乍一看,一切看起来都很好,但这个文件随着应用程序的增长就会产生一些问题。
我们违反了单一责任原则。我们面临合并冲突,我们的端点不可移植,并且很难在文件中找到端点位置。
我们需要将责任分配给负责的模块,因此每个模块都负责暴露其端点。
然后我们可以在API服务中汇总和加入整个端点。
我们来看看如何借助Angular 依赖注入和multi选项来实现这一点。
创建API服务
首先,我们需要创建负责执行聚合并暴露应用程序端点的服务。
import {Inject, Injectable, InjectionToken} from '@angular/core';
export const END_POINTS = new InjectionToken('END_POINTS');
@Injectable()
export class API {
private readonly _baseUrl = environment.BASE_URL;
endPoints: EndPoints;
constructor(@Inject(END_POINTS) private _endPoints) { }
}
api.service.ts
我们有一个代表每个端点的InjectionToken
。现在让我们看看我们如何填充END_POINTS
token。
创建认证模块
每个模块需要创建两个附加文件。
export const api = {
login: "/auth/login",
logout: "/auth/logout",
signup: "/auth/signup",
};
auth.api.ts
顾名思义,这个文件将负责Auth端点。
interface EndPoints {
login: string;
logout: string;
signup: string;
}
auth.d.ts
我们仍然想使用typescript声明合并的优势。
从根本上说,合并的机制是把双方的成员放到一个同名的接口里。
现在,typescript会将每个端点合并到EndPoints
接口,以便我们可以自动补全。
接下来,我们将Auth
端点提供给相应模块中的Angular 依赖注入,在我们的例子中为Auth
模块。
import { END_POINTS } from "../config/api";
import { api } from "./auth.api";
const AUTH_API = { provide: END_POINTS, multi: true, useValue: api };
@NgModule({
...
providers: [AuthService, AUTH_API]
})
export class AuthModule {
}
auth.module.ts
你可以把multi
选项想象成一个数组。每次我们添加一个新的provider
时,Angular将provider
推入数组中。
因此,如果我们返回到我们的API服务并打印_endpoints
属性,我们将看到数组中有一个项目 -- Auth
端点。
END_POINTS Provider
很好,现在我们只需要将我们的端点平放到一个大对象上。
@Injectable()
export class API {
...
constructor(@Inject(END_POINTS) private _endPoints) {
this.endPoints = _endPoints.reduce((acc, current) => {
return {
…current,
…acc
};
}, {});
}
}
api.service.ts
最后,我们创建一个简单的方法来帮助我们解析url。
class API {
...
resolve(url: string, params?) {
if (!params) {
return `${this._baseUrl}${url}`;
}
const resolved = Object.keys(params).reduce((acc, param) => {
return acc.replace(`:${param}`, params[param]);
}, url);
return `${this._baseUrl}${resolved}`;
}
}
api.service.ts(译者注:此函数用于替换url中:id
部分为真实参数)
现在,我们可以在我们需要的每项服务中使用API服务。为了简洁起见,我已经添加了一个Todos
模块,其中我们描述了相同的流程。 例:
总结
在本文中,我们目睹了Angular 依赖注入的强大功能以及我们如何利用multi
选项。通过这种改变,我们不太会受到合并冲突的影响,并且这些模块可以随API一起移植,因此我们可以将它们与其他应用程序一起使用。我们也避免违反单一责任原则,并且我们的代码组织得更好。