利用angular依赖注入的multi选项更好的组织代码(翻译)

 

在几乎所有的应用程序中都有一个将所有应用的端点都抛出的文件。如果你正在使用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_POINTStoken。

创建认证模块

每个模块需要创建两个附加文件。

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

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一起移植,因此我们可以将它们与其他应用程序一起使用。我们也避免违反单一责任原则,并且我们的代码组织得更好。

原文链接

猜你喜欢

转载自my.oschina.net/u/3523984/blog/1624098
今日推荐