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, ..... };Copy the code
At first glance, everything looks fine, but this file can cause problems as the application grows.
We are violating the principle of single liability. We are facing merge conflicts, our endpoints are not portable, and it is difficult to find the endpoint location in the file.
We need to assign responsibility to responsible modules, so each module is responsible for exposing its endpoints.
We can then add the sum to the entire endpoint in the API service.
Let’s see how to do this with Angular dependency injection and multi options.
Creating an API Service
First, we need to create the service responsible for performing the aggregation and exposing the application endpoint.
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) { }
}
Copy the code
api.service.ts
We have an InjectionToken representing each endpoint. Now let’s see how we populate the END_POINTS token.
Creating an Authentication Module
Each module needs to create two additional files.
export const api = {
login: "/auth/login".logout: "/auth/logout",
signup: "/auth/signup"};Copy the code
auth.api.ts
As the name implies, this file will be responsible for the Auth endpoint.
interface EndPoints {
login: string;
logout: string;
signup: string;
}
Copy the code
auth.d.ts
We still want to use typescript to declare the benefits of merging.
Basically, the mechanism of merging is to put the members of both parties into an interface with the same name.
Now, typescript merges each endpoint into the EndPoints interface so that we can complete it automatically.
Next, we provide the Auth endpoint to Angular dependency injection in the corresponding module, in our case the Auth module.
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 {
}
Copy the code
auth.module.ts
You can think of the Multi option as an array. Every time we add a new provider, Angular pushes the provider into the array.
So, if we go back to our API service and print the _endpoints property, we’ll see an item in the array — the Auth endpoint.
END_POINTS Provider
Good, now we just need to lay our endpoints flat on a big object.
@Injectable()
export class API {
...
constructor(@Inject(END_POINTS) private _endPoints) {
this.endPoints = _endPoints.reduce((acc, current) => {
return{... Current,... acc }; }, {}); }}Copy the code
api.service.ts
Finally, let’s create a simple method to help us parse urls.
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}`; }}Copy the code
Api.service. ts this function is used to replace the url:id
Some are real parameters)
Now we can use API services in every service we need. For brevity, I have added a Todos module where we describe the same process. Ex. :
conclusion
In this article, we’ve seen the power of Angular dependency injection and how we can leverage the Multi option. With this change, we are less affected by merge conflicts, and these modules can be ported with the API, so we can use them with other applications. We also avoided violating the single liability principle, and our code was better organized.
The original link