3
\$\begingroup\$

I have an Ionic application, this application contains set of pages and services. Since I'm working with Ionic and Angular I decided to build reusable code for different projects, for example:

HTTP service: in this service I want to centralize the code that manages the communication with server side to achieve the reusable concept and the change will be in one place.

My Http.service code is:

import {Injectable} from "@angular/core";
import {AuthenticationService} from "./authentication.service";
import {Observable} from "rxjs/Observable";
import {HttpClient, HttpHeaders} from "@angular/common/http";
import {AlertController, InfiniteScroll, Loading, Refresher} from "ionic-angular";
import 'rxjs/add/observable/forkJoin';

@Injectable()
export class HttpConnectionService {

  constructor(
    private http: HttpClient,
    private authService: AuthenticationService,
    private alertCtrl: AlertController
  ) {}

  httpRequests( options: ForkOptions) {
    let observables = [
      ...options.requests.map((request) =>  request.observable)
    ];
    console.log(observables);
    Observable.forkJoin(observables).subscribe(
      (results) => {
        for(let i = 0; i < results.length; i++) {
          this.responseHandler(results[i], options.requests[i]);
        }
      }, (error) => {
        this.errorHandler(error, options);
      }, () => {
        this.completeHandler(options);
      }
    );
  }

  createObservable(requestOptions: RequestOptions) {
    switch(requestOptions.method) {
      case 'post' : case 'delete' :
        return this.postDelete(requestOptions);
      case 'get':
        return this.get(requestOptions);
    }
  }

  private postDelete(requestOptions: RequestOptions) {
    return this.http[requestOptions.method](requestOptions.url, requestOptions.data);
  }

  private get(requestOptions: RequestOptions) {
    return this.http.get(requestOptions.url);
  }

  /**
   *
   * @param {RequestOptions} requestOptions identify different attributes of the request.
   */
  httpRequest(requestOptions: RequestOptions) {
    // send the http request and use the method attribute

    // if there is observable sent with request
    let observable = requestOptions.observable;
    if(observable == undefined){
      // if there is no observable, create one
      observable = this.createObservable(requestOptions);
    }
    observable.subscribe(
      (response: any) => {
        // call the response handler
        this.responseHandler(response, requestOptions);
      }, (error) => {
        // call the error handler
        this.errorHandler(error, requestOptions);
      }, () => {
        // call the complete handler
        this.completeHandler(requestOptions);
      }
    );
  }

  private responseHandler(response, requestOptions: RequestOptions) {
    // if the response success, execute the success call back
    if(response.isSuccess) {
      requestOptions.successCallBack(response.result);
      // check if there is infinit scroller and the response is empty, then disable the infinit scroller
      if(requestOptions.infinitScroller && response.result.length == 0) {
        requestOptions.infinitScroller.enable(false);
      }
    }else {
      // if the response is not success, check if the notSuccessCallBack is defined,
      // if notSuccessCallBack is defined, execute it, other wise, execute the default notSuccess callBacl
      if(requestOptions.notSuccessCallBack) {
        // execute the provided not success callBack
        requestOptions.notSuccessCallBack(response);
      }else if(requestOptions.useDefaultNotSuccessCallBack){
        // execute the default not success callBack
        this.defaultNotSuccessResponse(response);
      }
    }
  }

  private errorHandler(error, requestOptions: RequestOptions  | ForkOptions) {
    // check for the provided error callBack.
    if(requestOptions.errorCallBack) {
      // execute the provided callBack
      requestOptions.errorCallBack(error);
    }else if(requestOptions.useDefaultErrorCallBack){
      // if u can default error handler
      this.defaultErrorHandler(error, requestOptions);
    }
  }

  private completeHandler(requestOptions: RequestOptions  | ForkOptions) {
    if(requestOptions.completeCallBack) {
      requestOptions.completeCallBack();
    }
    this.turnOffExternalComponents(requestOptions);
  }

  private defaultNotSuccessResponse(response) {
    this.alertCtrl.create({
      title: "Error!",
      subTitle: response.message
    }).present();
  }

  /**
   *
   * @param error: the error object
   * @param {RequestOptions} requestOptions: contains attributes about the request
   * used as params to access the external components when turning them off.
   */
  private defaultErrorHandler(error, requestOptions: RequestOptions | RequestOptions | ForkOptions) {
    // turn off the active components.
    this.turnOffExternalComponents(requestOptions);
    // create alert for the client.
    this.alertCtrl.create({
      title: "Error!",
      subTitle: error.message
    }).present();
  }

  private turnOffExternalComponents(requestOptions: RequestOptions  | ForkOptions) {
    // set the refresher to complete
    if(requestOptions.refresher) {
      requestOptions.refresher.complete();
      // after refreshing, enable the infinit scroller.
      if (requestOptions.infinitScroller) {
        requestOptions.infinitScroller.enable(true);
      }
    }
    // set the infinit Scroller to complete.
    // and turn on the infinit scroller.
    if(requestOptions.infinitScroller) {
      requestOptions.infinitScroller.complete();
    }

    // check if there is loader, and turn it off.
    if(requestOptions.loader) {
      requestOptions.loader.dismissAll();
    }
  }
}

export interface RequestOptions {
  observable?: any;
  url?:string;
  method?: string;
  successCallBack?: any;
  notSuccessCallBack?: any;
  useDefaultNotSuccessCallBack?: boolean;
  errorCallBack?: any;
  useDefaultErrorCallBack?: boolean;
  completeCallBack? : any;
  sendToken?: boolean;
  data?: any;
  refresher?:Refresher;
  infinitScroller?: InfiniteScroll;
  loader?: Loading;
}

export interface ForkOptions {
  requests: RequestOptions[];
  useDefaultNotSuccessCallBack?: boolean;
  errorCallBack?: any;
  useDefaultErrorCallBack?: boolean;
  completeCallBack? : any;
  refresher?:Refresher;
  infinitScroller?: InfiniteScroll;
  loader?: Loading;
}

For now, I don't know if this is a good practice or not.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.