Daniel Patrick
Daniel Patrick

Reputation: 4340

Chained rxjs Observable operators

I'm relatively new to the ReactiveX principles, but I'm a big fan so far of what I've learned. I have a challenge that I've put a little thought into, but I'd like to get a more experienced opinion on:

I have a few methods which return an Observable. Each one creates an Observable in a similar manor and then chains the same exact operators. Is there any way of abstracting those operators away such that I don't have to repeat this code each method.

For example, this is what I have right now:

    public get(endpoint: string, options?: RequestOptions): Observable<any> {
      return this.http.get(endpoint, requestOptions)
        .map((response: Response) => {
          let responseBody = response.json();
          return responseBody;
        })
        .catch((error: Response) => {
            let responseError = new ErrorResponse(error.status.toString(), error.json());
            return Observable.throw(responseError);
        })
        .publishReplay()
        .refCount()
        .share();
    }

    public put(endpoint: string, body: any, options?: RequestOptions): Observable<any> {
      return this.http.put(endpoint, body, requestOptions)
        .map((response: Response) => {
          let responseBody = response.json();
          return responseBody;
        })
        .catch((error: any) => {
          this.logger.logRequestError('PUT', endpoint, error);
          return Observable.throw(error);
        })
        .publishReplay()
        .refCount()
        .share();
    }

I'd like to take the map, catch, publishReplay, refCount, share operators and put them in their own operator, such that I can do something like this:

    public get(endpoint: string, options?: RequestOptions): Observable<any> {
      return this.http.get(endpoint, requestOptions).myOperator();
    }

    public put(endpoint: string, body: any, options?: RequestOptions): Observable<any> {
      return this.http.put(endpoint, body, requestOptions).myOperator();
    }

    // define myOperator as something like:

        .map((response: Response) => {
          let responseBody = response.json();
          return responseBody;
        })
        .catch((error: Response) => {
            let responseError = new ErrorResponse(error.status.toString(), error.json());
            return Observable.throw(responseError);
        })
        .publishReplay()
        .refCount()
        .share();

    // end definition

Upvotes: 0

Views: 105

Answers (1)

Mark van Straten
Mark van Straten

Reputation: 9425

Would something like this work for you? Using bind() you can defer the execution of your http call. I don't know which library you are using, if http.get() returns an Observable then you can just call it and pass the returned observable to handleHttpCall because Observables are (almost always) lazy and will not run code until subscribed upon.

public get(endpoint:string, options?: RequestOptions): Observable<any> {
  return handleHttpCall(this.http.get.bind(endpoint, requestOptions));
}

private handleHttpCall(httpAction) {
  return httpAction()
       .map((response: Response) => {
          let responseBody = response.json();
          return responseBody;
        })
        .catch((error: Response) => {
            let responseError = new ErrorResponse(error.status.toString(), error.json());
            return Observable.throw(responseError);
        })
        .publishReplay()
        .refCount()
        .share();
}

Upvotes: 0

Related Questions