We're currently working on an Angular4 app and looking for feedback on architecture for services.
The five 'modules' of the app are:
- one
- two
- three
- four
- five
Currently we have one data service that specific to one, however, the abstract class ApiService could be imported across the other four modules (see code below).
Here are some options on what I'm thinking:
Option 1:
Move the abstract class ApiService into our shared folder module i.e. the shared folder module gets imported into each of the five modules.
Then create a service specific to each module which is inherited from ApiService. This would make it easy to manage each individual service.
Option 2: Move the abstract class into our shared folder and create a global service that contains all the api calls for all of the five modules. That way we have a single service to manage all API connections. However, the file might get a bit big and hard to manage. Thoughts on organizing?
Option 3: Scrap the observable services all together and go with something like ngrx/store to handle state.
I'm looking for feedback on the data service architecture.
module-one-data-service.ts
import { Injectable } from '@angular/core';
import { Http, Response, Headers, RequestOptions } from '@angular/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import { IPosition } from './position.model';
import { IPositionReference } from '../shared/side-pane/position-reference.model';
import { Subject } from 'rxjs/Subject';
export abstract class ApiService {
protected BASE_URL = 'http://justtheurl.com';
protected baseAndModuleUrl: string;
private OPTIONS = new RequestOptions({
headers: new Headers({
'Authorization' : 'Basic thisIsJustForTesting'
}),
withCredentials: true
});
constructor(private http: Http, private module: string) {
this.baseAndModuleUrl = `${this.BASE_URL}${module}`;
}
public getBaseModuleUrl() { return this.baseAndModuleUrl; }
protected fetch(apiAction: string): Observable<any> {
return this.http
.get(`${this.baseAndModuleUrl}${apiAction}`, this.OPTIONS)
.map((res: Response) => res.json().data);
}
protected post(apiAction: string, positions: Object[]): Observable<any> {
return this.http
.post(`${this.baseAndModuleUrl}${apiAction}`, positions, this.OPTIONS)
.map((res: Response) => res.json());
}
protected upload(apiAction: string, file: FormData): Observable<any> {
return this.http
.post(`${this.baseAndModuleUrl}${apiAction}`, file, this.OPTIONS)
.map((res: Response) => res.json());
}
}
@Injectable()
export class ModuleOneDataService extends ApiService {
public editableValues = new Subject<any>();
constructor(http: Http) { super(http, '/api/module/one'); }
public fetchTree(): Observable<IPosition[]> { return this.fetch('/tree'); }
public fetchList(): Observable<IPosition[]> { return this.fetch('/list'); }
public fetchIndividual(id: string): Observable<IPositionReference> { return this.fetch(`/node/${id}`); }
public savePositionsToSubgraph(positions: Object[]): Observable<any> { return this.post('/subgraph/upsert', positions); }
public mergeSubraphToMaster(): Observable<Object> { return this.post('/subgraph/merge', [{}]); }
}