4

We have http calls like:

this.http.get(`${environment.baseUrl}/api/v.1/reports/...`, 
{ responseType: ResponseContentType.Blob })

which returns blob pdfs which we further on save through FileSaver.

Problem is if server returns 4XX response with some application/json and message in body. In that case, we cannot find a way how to access it as responseType has to be set prior to request and cannot be altered later.

Is there any elegant solution for it?

dee zg
  • 13,793
  • 10
  • 42
  • 82
  • Which specific code(s) are you getting? https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_errors – JGFMK Aug 03 '17 at 08:18
  • i want the same behavior (receiving json with error message) for any 4xx response. for the sake of discussion, lets say server returns 400 with `{errorCode:1, errorMessage:"do something"}` – dee zg Aug 03 '17 at 08:20
  • Authentication failures and timeouts for example would have entirely different solution.. So request is too open ended... – JGFMK Aug 03 '17 at 08:23
  • ok, lets stick to 400 response code. – dee zg Aug 03 '17 at 08:24
  • For 400 https://angular.io/api/http/Response#statusText I'd log that and see if the message gives you more info. Not sure if that will give you more than Bad Request. Let me know – JGFMK Aug 03 '17 at 08:32
  • there might be an missunderstanding. client code doesn't and cannot know what is wrong. imagine a general case where you have a form with 10 fields based on which server compiles PDF on the fly. if all goes good you get PDF (read blob(), etc...) but if server validation fails you get 400 with application/json body and error json in it which you, of course, want to show to user. but since your angular request contains definition that responseType is blob, it can't read `response.json()`. – dee zg Aug 03 '17 at 08:36
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/150918/discussion-between-jgfmk-and-dee-zg). – JGFMK Aug 03 '17 at 08:39
  • I think this thread is likely to give best answer https://stackoverflow.com/questions/35326689/how-to-catch-exception-correctly-from-http-request/35329086#35329086 - subscribe/catch http://reactivex.io/documentation/operators.html#error - retry or retrywhen was the other possibility - but catch seemed more logical – JGFMK Aug 03 '17 at 09:16
  • i actually came up to something. let me post as answer and please give your opinion. – dee zg Aug 03 '17 at 09:22
  • Use a plunker and link it is probably best.. – JGFMK Aug 03 '17 at 09:25

1 Answers1

2

I did a few tests and this is what i did so far. It works, all as expected. But i will not accept it as answer yet but leave for some time for a community to review. If someone sees problems with this approach, please point them out in comments.

ErrorMessage is of simple format:

{ message:string }

Service:

getPDF() {
    return this.http.get(`${environment.baseUrl}/api/v.1/reports/...`, { responseType: ResponseContentType.Blob })
      .map((res) => {
        return {
          blob: new Blob([res.blob()], { type: 'application/pdf' }), filename: this.parseFilename(res)
        }
      })
      .catch((res) => {
        let fileAsTextObservable = new Observable<string>(observer => {
          const reader = new FileReader();
          reader.onload = (e) => {
            let responseText = (<any>e.target).result;

            observer.next(responseText);
            observer.complete();
          }
          const errMsg = reader.readAsText(res.blob(), 'utf-8');
        });

        return fileAsTextObservable
          .switchMap(errMsgJsonAsText => {
            return Observable.throw(JSON.parse(errMsgJsonAsText));
          })
      });
  }
dee zg
  • 13,793
  • 10
  • 42
  • 82
  • Can I add an updated version of your snippet for the latest RxJs? Btw, the Angular team seems not interested in the requested feature. – LppEdd Feb 13 '19 at 13:17