Today I faced a challenge while working on an abstract http service implementation. The goal of this service is to serve as a base for extending all other http services.
Here's the current implementation, excluding some methods for illustration:
@Injectable()
export abstract class HttpWrapper<T> {
private options: RequestOptions;
constructor(private http: Http, private endpointUrl: string) {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
this.options = new RequestOptions({ headers: headers });
}
public getAll(): Observable<T[]>{
return this.http.get(this.endpointUrl, this.options)
.map(this.extractAll)
.catch(this.handleError);
}
abstract handleError(error: any):Observable<Response>;
abstract extractOne(res: Response):T;
abstract extractAll(res: Response):T[];
}
When attempting to use the abstract HttpWrapper, I proceed as follows:
@Injectable()
export class BlastReportService extends HttpWrapper<Item> {
constructor(http: Http) {
super(http,'/api/items');
}
handleError(error: any):Observable<Response>{
//Handling error
return Observable.throw(error);
}
extractAll(res: Response):Item[]{
let body = res.json();
let formattedBody = body.map((item: Item) => {
item = new Item(item);
return blastReport;
});
return formattedBody || [{}];
}
}
However, this leads to a compilation error:
Type 'Observable<Response>' is not assignable to type 'Observable<T[]>'.
Type 'Response' is not assignable to type 'T[]'.
Property 'find' is missing in type 'Response'.
This error is baffling because the method extractAll clearly returns Item[] and is utilized when mapping the results obtained from the server.
I decided to implement this abstract HttpWrapper approach to maintain DRY principles. Although I'm unsure if it's the most effective strategy.