3

I am working with a web API service (DocRaptor) that returns a PDF as the response. While initially working with the API, I was able generate a PDF and view the PDF on their site. I received a 200 Status Code telling me that the response was successful. However, the result of the post was still returned as an error on the Angular side using this code:

    return this.http
  .post("https://docraptor.com/docs", {
    headers: {
      "Content-Type": "application/json"
    },
    user_credentials: "WEB_API_KEY",
    doc: {
      test: true,
      name: "testDocument.pdf",
      document_content: documentContent,
      type: "pdf"
    }
  })
  .subscribe(
    res => {
      console.log(res);
    },
    err => {
      console.log("Error occured: " + err);
    }
  );

I am assuming this is because the code was expecting JSON as a result, and instead the API returned a PDF.

Angular's documentation on Requesting non-JSON Data does not go into enough detail on how to consume the response using the HttpClient (and neither does DocRaptor's for that matter). When debugging, I can't tell (using the Network tab in Chrome) that the API call is even being sent, or a response returned, using the code below. This is likely a problem in the syntax below, but the following code is an approach I've tried using the documentation I know that's available:

   return this.http
  .post("https://docraptor.com/docs", {
    responseType: "blob",
    headers: {
      "Content-Type": "application/json",
      Accept: "application/pdf"
    },
    user_credentials: "WEB_API_KEY",
    doc: {
      test: true,
      name: "testDocument.pdf",
      document_content: documentContent,
      type: "pdf"
    }
  })
  .pipe(tap(data => this.downloadFile(data, "application/pdf")));

UPDATE:

I have rearchitected my code as suggested in the responses here. However, I am still receiving the original error, which is that I'm getting a 200 Status back from DocRaptor API, but Angular's HttpClient isn't parsing the response as a PDF. I've added in the headers to accept a PDF, and I still receive an error message that "Unexpected token % in JSON at position 0".

repl.component.ts

  generatePdf() {
    var htmlCard = this.cards.filter((card: Card) => card.language === "html")[0];
    var cssCard = this.cards.filter((card: Card) => card.language === "css")[0];

    var documentContent = this.generateCode(
      htmlCard.editorContent,
      cssCard.editorContent
    );

    this.docRaptorService.generatePdf(documentContent).subscribe(results => {
      let blob = results;
      let filename = "testDocument.pdf";
      FileSaver.saveAs(blob, filename);
    });
  }

doc-raptor.service.ts

  generatePdf(documentContent: string) {
    return this.http
      .post("https://docraptor.com/docs", {
        headers: {
          "Content-Type": "application/json",
          Accept: "application/pdf"
        },
        user_credentials: "WEB_API_KEY",
        doc: {
          test: true,
          name: "testDocument.pdf",
          document_content: documentContent,
          type: "pdf"
        },
        responseType: "blob"
      })
      .pipe(
        tap(
          data => console.log(documentContent, data),
          error => console.log(documentContent, error)
        )
      );
  }
4
  • in your second example, the Observable isn't being subscribed to. Can't tell if you're subscribing elsewhere, but Observables will do nothing until subscribed to. Commented Dec 11, 2018 at 19:48
  • I'm unsure how pipe and tap work in relation to subscribe. Angular's documentation omits subscribe from this section, so I am assuming that pipe and tap are used in place of subscribe when you are trying to consume non-JSON data in the return. Commented Dec 11, 2018 at 20:02
  • pipe and tap are operators, and are a core part of Observable streams. They alter the data as it comes through the stream, in this case blobbing the data into an object. Angular omits subscribe here because it's considered bad practice to subscribe to Observables in a service, and instead return the Observable to a caller. Observables only run when subscribed to. Commented Dec 11, 2018 at 20:07
  • The below link solves my issue.. stackoverflow.com/questions/50332447/… Commented Jun 10, 2020 at 14:54

2 Answers 2

1

I also had a similar need where my Api returned a Pdf file object. I first tried by passing headers object with "Accept" set as "Accept": "application/pdf". But that did not work.

Then I simply set "responseType" in httpOptions as:

this._httpClient.post(apiUrl, filterParams, { responseType: 'blob' });

and it worked.

Sign up to request clarification or add additional context in comments.

Comments

0
 .pipe(tap(data => this.downloadFile(data, "application/pdf")));

You have to subscribe to an Observable before it will do anything. The Angular example is returning the Observable with a tap operator 'attached' to it. Your own example is returning the Subscription, which is useless to anything calling your method.

It's the recommended design pattern for Angular services; the service creates the Observable, which is like a contract for a stream of work and data transformations, then the caller can subscribe to it and get the result of the work.

1 Comment

See my update to the original post. I've rearchitected the solution as you and Angular's documentation have suggested. That still doesn't fix my original problem, which is that I can't access the non-JSON response from the web API using Angular's HttpClient.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.