Search code examples
angulartypescriptrxjsdelayrxjs-pipeable-operators

Http post request ignoring piped delay


In my service class I'm firing post request like this

// my-service.service.ts
sendRequest(
    param: string
  ): Observable<HttpResponse<string>> {
    return this.http.post<HttpResponse<string>>("", {
      param
    }).pipe(
      retry(3),
    )
}

Thus the component is subscribing to the returned Observable by

// my-component.ts
this.myService.sendRequest(
      ""
    ).subscribe(
      res => {
        console.log(res)
      },
      (err: HttpErrorResponse) => {
        console.log(err.message)
      }
)

As you notice I'm doing post requests to "" that is converted into http://localhost:4200 that doesn't exist, so every post request will result in a Cannot POST / response (404).

I'm not getting why by adding a delay at

this.myService.sendRequest(
      ""
    ).pipe(delay(10000)).subscribe(
      res => {
        console.log(res)
      },
      (err: HttpErrorResponse) => {
        console.log(err.message)
      }
)

will cause the error response to ignore it and print on the console as long as the request completes thus ignoring it.


Solution

  • delay only delays emissions, not errors.

    I opened a discussion some time ago in the rxjs' repo -> https://github.com/ReactiveX/rxjs/discussions/6519

    I think the only way of achieving what you want would be something like:

    this.myService.sendRequest(
      ""
    ).pipe(
      delay(10000),
      catchError(err => timer(10000).pipe(
        switchMap(() => throwError(() => err))
      ))
    )
    

    If you think that's ugly, you can always encapsulate it in a custom operator:

    const delayEverything = <T>(ms: number) => (source: Observable<T>) =>
      source.pipe(
        delay(ms),
        catchError(err => timer(ms).pipe(switchMap(() => throwError(() => err))))
      )
    
    // ... and then use it as a regular operator
    
    this.myService.sendRequest('').pipe(
      delayEverything(10000)
    )