File

projects/ngx-yii2-rest/src/lib/services/end-point.service.ts

Index

Properties
Methods

Constructor

constructor(http: HttpClient)
Parameters :
Name Type Optional
http HttpClient no

Methods

Public _headerOptions
_headerOptions()

Sets the headers for most requests.

Returns : { headers: any; }

RequestOptions

Public addHeader
addHeader(id: string, value: string)

Appends headers for each request.

Parameters :
Name Type Optional
id string no
value string no
Returns : this
Public addParam
addParam(id: string, value: any)

Adds a parameter onto an existing parameter if its an array.

Parameters :
Name Type Optional
id string no
value any no
Returns : this

EndPointService

Public deleteOne
deleteOne(id: number, field: string)

Deletes a single item

Parameters :
Name Type Optional Default value
id number no
field string no null
Returns : any

Observable

Public endPointUrl
endPointUrl()

Returns the base endpoint url for this service.

Returns : string
Public fetchAll
fetchAll(id: any, payloadOnly: )

Fetches multiple items and separates them into pages.

Parameters :
Name Type Optional Default value
id any no null
payloadOnly no false
Returns : any
Public fetchComplete
fetchComplete()

Fetches all data from the server using multiple requests (use sparingly, if using in every circumstance change server default or if results change frequency and are not stable) 'pageSizeLimit' => [1] is a hacky workaround on server to fetch all results.

Returns : any
Protected fetchEndPoint
fetchEndPoint()

Fetches the endpoint url.

Returns : string

string

Public fetchOne
fetchOne(id: number)

Fetches a single item.

Parameters :
Name Type Optional
id number no
Returns : any

Observable

Public fetchResult
fetchResult()

Fetches multiple items and returns as one object.

Returns : any
Public getFilters
getFilters()

Fetches the current filters.

Returns : any

Array<{name: string, value: string, operator?: string}>

Public initModel
initModel(data: any)

Initiates each instance of the model.

Parameters :
Name Type Optional Description
data any no

The data for the model.

Returns : BaseModel
Public insertOne
insertOne(params: any)

Inserts a single record.

Parameters :
Name Type Optional
params any no
Returns : any
Public paramsToString
paramsToString()

Converts parameters set to a string that is to be sent to the server.

Returns : any

string

Public primaryKey
primaryKey()

The primary key name.

Returns : string
Public setParam
setParam(id: string, value: any)

Sets a single parameter.

Parameters :
Name Type Optional
id string no
value any no
Returns : this

EndPointService

Public setParams
setParams(params: any)

Sets a group of parameters.

Parameters :
Name Type Optional
params any no
Returns : this

EndPointService

Public updateOne
updateOne(id: number, params: any)

Updates a single record.

Parameters :
Name Type Optional
id number no
params any no
Returns : any

Properties

Public allowedParams
allowedParams: Array<string>
Type : Array<string>
Default value : [ 'perPage', 'page', 'expand', 'filters', 'sort', 'fields' ]

Parameters that are allowed by setParam and addParam

Public expand
expand: Array<string>
Type : Array<string>
Default value : []

The expandable relationships.

Public fields
fields: Array<string>
Type : Array<string>
Default value : []

The fields to select

Public filters
filters: Array<literal type>
Type : Array<literal type>
Default value : []

The filters to apply on the search.

Public headers
headers: literal type
Type : literal type
Default value : { 'Content-Type': 'application/json', 'Accept': 'application/json' }

The headers to send one each request.

Public http
http: HttpClient
Type : HttpClient

Angular http library

Public page
page: number
Type : number
Default value : 1

Current page index (perPage times the current offset)

Public perPage
perPage: number
Type : number
Default value : 20

The number of items to show per page.

Public sort
sort: Array<literal type>
Type : Array<literal type>
Default value : []

The fields to sort by

import objectToParams from '../utils/object.to.params';
import {Observable} from 'rxjs';
import {map} from 'rxjs/operators';
import {Injectable} from '@angular/core';
import {BaseModel} from '../models/base.model';
import isJsObject from '../utils/is.js.object';
import {HttpClient, HttpHeaders, HttpResponse} from '@angular/common/http';

@Injectable()
export abstract class EndPointService {

  /**
   * Angular http library
   */
  public http: HttpClient;

  /**
   * The number of items to show per page.
   */
  public perPage = 20;

  /**
   * Current page index (perPage times the current offset)
   */
  public page = 1;

  /**
   * The expandable relationships.
   */
  public expand: Array<string> = [];

  /**
   * The fields to select
   */
  public fields: Array<string> = [];

  /**
   * The filters to apply on the search.
   */
  public filters: Array<{name: string, value: string, operator?: string}> = [];

  /**
   * The fields to sort by
   */
  public sort: Array<{key: string, direction: string}> = [];

  /**
   * Parameters that are allowed by setParam and addParam
   */
  public allowedParams: Array<string> = [
      'perPage',
      'page',
      'expand',
      'filters',
      'sort',
      'fields'
  ];

  /**
   * The headers to send one each request.
   */
  public headers: {[key: string]: string} = {
      'Content-Type': 'application/json',
      'Accept': 'application/json'
  };

  /**
   * The primary key name.
   */
  public abstract primaryKey(): string;

  /**
   * Initiates each instance of the model.
   *
   * @param data The data for the model.
   */
  public abstract initModel(data: any): BaseModel;

  /**
   * Returns the base endpoint url for this service.
   */
  public abstract endPointUrl(): string;

  constructor(http: HttpClient) {
      this.http = http;
  }

  /**
   * Sets the headers for most requests.
   *
   * @returns RequestOptions
   */
  public _headerOptions() {
      const headers = new HttpHeaders(this.headers);
      return { headers: headers };
  }

  /**
   * Appends headers for each request.
   *
   * @param id
   * @param value
   */
  public addHeader(id: string, value: string) {
      this.headers[id] = value;
      return this;
  }

  /**
   * Sets a single parameter.
   *
   * @param id
   * @param value
   * @returns EndPointService
   */
  public setParam(id: string, value: any) {
      if (typeof this[id] === 'undefined' || this.allowedParams.indexOf(id) === -1) {
          throw new Error(`Invalid parameter '${id}' set on endpoint.`);
      }
      this[id] = value;
      return this;
  }

  /**
   * Adds a parameter onto an existing parameter if its an array.
   * @param id
   * @param value
   * @returns EndPointService
   */
  public addParam(id: string, value: any) {
      if (this[id] !== undefined && Array.isArray(this[id])) {
          value = this[id].concat(value);
      }
      this.setParam(id, value);
      return this;
  }

  /**
   * Sets a group of parameters.
   *
   * @param params
   * @returns EndPointService
   */
  public setParams(params: any) {
      Object.keys(params).map((id) => {
          this.setParam(id, params[id]);
      });
      return this;
  }

  /**
   * Fetches the current filters.
   *
   * @returns Array<{name: string, value: string, operator?: string}>
   */
  public getFilters() {
      return this.filters;
  }

  /**
   * Converts parameters set to a string that is to be sent to the server.
   *
   * @returns string
   */
  public paramsToString() {
      const params = {
          'per-page': this.perPage,
          expand: this.expand.join(','),
          fields: this.fields.join(','),
          filters: this.filters.length > 0 ? this.filters : [],
          page: this.page,
          sort: this.sort.map((sort) => {
              return (sort.direction === 'DESC' ? '-' : '') + sort.key;
          }).join(',')
      };
      return objectToParams(params);
  }

  /**
   * Updates a single record.
   */
  public updateOne(id: number, params: any): any {

      const httpUrl = this.fetchEndPoint() + '/' + id + '?' + this.paramsToString();
      const body = JSON.stringify(params);
      const options = this._headerOptions();
      return this.http.patch<any>(httpUrl, body, options)
        .pipe(
          map(res => {
            return this.initModel(res);
          })
        );
  }

  /**
   * Inserts a single record.
   */
  public insertOne(params: any): any {

      const httpUrl = this.fetchEndPoint() + '?' + this.paramsToString();
      const body = JSON.stringify(params);
      const options = this._headerOptions();

      return this.http.post<any>(httpUrl, body, options)
        .pipe(
          map(res => {
            return this.initModel(res);
          })
        );
  }

  /**
   * Fetches the endpoint url.
   *
   * @returns string
   */
  protected fetchEndPoint() {
      return this.endPointUrl();
  }

  /**
   * Fetches a single item.
   *
   * @param id
   * @returns Observable<Response>
   */
  public fetchOne(id: number) {
      return this.http.get<any>(this.fetchEndPoint() + '/' + id + '?' + this.paramsToString(), this._headerOptions())
        .pipe(
          map(res => {
            return this.initModel(res);
          })
        );
  }

  /**
   * Deletes a single item
   * @param id
   * @param field
   * @returns Observable<Response>
   */
  public deleteOne (id: number, field: string = null) {
      let httpUrl = this.fetchEndPoint() + '/' + id;
      if (field) {
          httpUrl += '/' + field;
      }
      const options = this._headerOptions();

      return this.http.delete<any>(httpUrl, options);
  }

  /**
   * Fetches multiple items and returns as one object.
   */
  public fetchResult(): any {
      return this.http.get(this.endPointUrl() + '?' + this.paramsToString(), this._headerOptions())
          .pipe(
            map((res: any) => {
              return {
                  payload: res.map((row: any) => {
                    return this.initModel(row);
                  })
              };
            })
          );
  }

  /**
   * Fetches multiple items and separates them into pages.
   */
  public fetchAll (id: any = null, payloadOnly = false) {

      let url = this.fetchEndPoint();
      if (id !== null) {
          url += `/${id}`;
      }
      url += '?' + this.paramsToString();
      const options = this._headerOptions();
      options['observe'] = 'response';
      return this.http.get(url, options)
          .pipe(
            map((res: HttpResponse<any>) => {
              if (payloadOnly) {
                  return res.body.map((row: any) => {
                      return this.initModel(row);
                  });
              } else {
                const data = res.body;
                const meta = res.headers
                  .keys()
                  .reduce((accum, key) => {
                    const newKey = (key.charAt(0).toLowerCase() + key.slice(1)).replace(/-/g, '');
                    accum[newKey] = res.headers.get(key);
                    return accum;
                  }, {});
                // Added for backward compatibility.
                meta['page'] = res.headers.get('X-Pagination-Current-Page');
                meta['pageCount'] = res.headers.get('X-Pagination-Page-Count');
                meta['totalCount'] = res.headers.get('X-Pagination-Total-Count');
                meta['perPage'] = res.headers.get('X-Pagination-Per-Page');
                return {
                    meta: meta,
                    payload: isJsObject(data)
                        ? Object.keys(data).map((key: any) => this.initModel(data[key]))
                        : data.map((row: any) => this.initModel(row))
                };
              }
            })
          );
  }

  /**
   * Fetches all data from the server using multiple requests
   * (use sparingly, if using in every circumstance change server default or if results change frequency and are not stable)
   * 'pageSizeLimit' => [1] is a hacky workaround on server to fetch all results.
   */
  public fetchComplete() {
      return new Promise((resolve, reject) => {
          this.setParam('page', 1)
              .fetchAll()
              .subscribe(
                  (data: any) => {
                      const pageCount = Number(data.meta.pageCount);
                      if (pageCount < 2) {
                          resolve(data.payload);
                      } else {
                          let pagesUpdated = 1;
                          const combinedData: Array<any> = [];
                          combinedData.fill([], 0, pageCount - 1);
                          combinedData[0] = data.payload;
                          for (let i = 1; i < pageCount; i ++) {
                              this.setParam('page', i + 1)
                                  .fetchAll()
                                  .subscribe(
                                      (data2: any) => {
                                          pagesUpdated++;
                                          combinedData[Number(data2.meta.page) - 1] = data2.payload;
                                          // We merge into one once all data is retrieved to ensure correct order.
                                          if (pagesUpdated === pageCount) {
                                              let flattenedData: Array<any> = [];
                                              combinedData.forEach((data3) => {
                                                  flattenedData = flattenedData.concat(data3);
                                              });
                                              resolve(flattenedData);
                                          }
                                      },
                                      (err) => {
                                          reject(err);
                                      }
                                  );
                          }
                      }
                  },
                  (err) => {
                      reject(err);
                  }
              );
      });
  }
}

results matching ""

    No results matching ""