I am currently utilizing Angular 12.
To avoid duplicating the same service logic, I am experimenting with creating a base class that includes all HTTP methods and then extending a child class to utilize in the components.
crud.service.ts
@Injectable({
providedIn: "root"
})
export class CrudService {
protected endpoint: string;
protected listObservableType: any;
constructor(
private http: AppHttpClient
) {
}
list(query: {[key: string]: any}): Observable<any> {
const url = `${this.endpoint}`;
let param = ''
for (let key in query) {
param += `${key}=${query[key]}&`
}
return this.http.Get(`${url}?${param}`);
}
}
In order to utilize the base class, a child class can be created as follows:
@Injectable({
providedIn: "root"
})
export class CategoryService extends CrudService {
endpoint = 'category/';
}
By setting the endpoint
in the child class, it will override the parent class and streamline all repetitive CRUD operations.
Currently, everything is functioning correctly, but the return type of the list()
method is fixed as Observable<any>
.
I aim to dynamically set the return type by using the listObservableType
variable, where an interface can be assigned like so:
export class CategoryService {
listObservableType = Array<CategoryItem>;
}
Subsequently, the return type can be defined as:
list(): Observable<this.listObservableType> {
...
}
Although I am uncertain about the correct approach, the aforementioned logic does not seem to work as intended.
Stackblitz: https://stackblitz.com/edit/angular-dynamic-observable?file=src%2Fapp%2Fservices%2Fcrud.service.ts
Edit 2: Interfaces
Each child service requires the following interfaces:
Paginated list page
export interface CategoryListResponse {
count: number;
next: string;
previous: string;
results: Array<CategoryItem>;
}
export interface CategoryItem {
id: number;
title: string;
}
The list()
method will return an observable of CategoryListResponse
, while the get()
and create()
endpoints will return observables of CategoryItem
.