2

As I'm new to angular, I want to know what should be the best practice to achieve what I want.

I want to request an API until I have the result I want with intervals between requests.

I use two nested services (GiftsService and ApiService) :

gifts.service.ts :

import { Injectable } from '@angular/core';
import { URLSearchParams } from '@angular/http';
import { environment } from '../../../environments/environment';
import { Observable } from 'rxjs/Rx';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';

import { ApiService } from './api.service';
import { Gift } from '../models';

@Injectable()
export class GiftsService {
  constructor (
    private apiService: ApiService
  ) {}

  get(id): Observable<Gift> {
    return this.apiService.get('/gifts/' + id)
           .map(data => data);
  }
  ...

api.service.ts

import { Injectable } from '@angular/core';
import { environment } from '../../../environments/environment';
import { Headers, Http, Response, URLSearchParams } from '@angular/http';
import { Observable } from 'rxjs/Rx';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';

import { JwtService } from './jwt.service';

@Injectable()
export class ApiService {
  constructor(
    private http: Http,
    private jwtService: JwtService
    ) {}

  get(path: string, params: URLSearchParams = new URLSearchParams()): Observable<any> {
    return this.http.get(path, { headers: this.setHeaders(), search: params })
    .catch(this.formatErrors)
    .map((res:Response) => res.json());
  }
...

And I call GiftsService.get in a component like this :

this.giftsService.get(this.gift.id)
.subscribe(data => {
    // if data.status != "ok" retry
})

Update

Here how I did it

this.giftsService.get(this.gift.id)
      .switchMap(data => data.status !== 'success' ? Observable.throw(new Error('status not successful')) : Observable.of(data))
      .retryWhen(attempts => {
        return Observable
        .range(1,10)
        .zip(attempts, function(i) {
          return(i);
        })
        .flatMap(function(i) {
          return Observable.timer(1000);
        })
      })
      .subscribe((
        data => {
          this.gift = data
        })
      );
loicb
  • 587
  • 2
  • 6
  • 24
  • In Error function retry to hit the service for example this.giftsService.get(this.gift.id) .subscribe(data => { // if data.status != "ok" retry, error =>call the service...... = error }) – Venkateswaran R Mar 21 '17 at 09:21
  • You may use rxjs retrywhen operator like this: http://stackoverflow.com/questions/40175255/angular2-rxjs-how-to-retry-from-inside-subscribe – KKS Mar 21 '17 at 09:27

2 Answers2

1

You can do something like this:

this.giftsService.get(this.gift.id)
  .switchMap(data => data.status !== 'OK' ? Observable.throw() : Observable.of(data))
  .retryWhen(errors => { /* setup retry logic here */ })
  .subscribe(data => {})
Sasxa
  • 40,334
  • 16
  • 88
  • 102
0

You could the retryWhen operator in combination with range and timer.

get(path: string, params = new URLSearchParams()) {
   return this.http.get(path, { 
       headers: this.setHeaders(), search: params 
   })
   .map(response => {
     response = response.json();
     if(response.status !== 'ok') {
       throw new Error('status not okay');
     }
     return response;
   })
   .retryWhen(errors => {
     return Observable
       .range(1, 3 /* maximum retry attempts */)
       .zip(errors)
       .flatMap([attempt, error] => {
         if(attempt >= 3) {
           return Observable.throw(error);
         }
         return Observable.timer(attempt*500 /* the retry timeout which increases after each attempt */);
       })
   })
   .catch(this.formatErrors)
}
cyr_x
  • 13,987
  • 2
  • 32
  • 46