angularaws-lambdaaws-api-gateway

Issue consuming API that returns Base64 Excel file in Angular


I am facing difficulties consuming an API in Angular that returns an Excel file encoded in Base64. The API is configured in AWS API Gateway and uses a Lambda function to generate the file. Although the API response seems correct (tested in Insomnia/Postman), Angular cannot interpret the content properly.


Problem Details:

  1. API Response:
    When I make the request in Insomnia, I receive a response with status 200 OK, and the body contains the Base64-encoded Excel file. Here's an example of the response:

    UEsDBBQAAAAIA... (long Base64 string)
    
  2. Response Headers:
    The headers returned by the API include:

    Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet  
    Content-Disposition: attachment; filename="suitability-produtos-20251124-150728.xlsx"  
    Access-Control-Allow-Origin: *  
    
  3. Angular Configuration:
    In Angular, I am trying to consume the API with the following code:

    this.http.post('https://my-api.com/suitability-produtos-templates', {}, { responseType: 'blob' })
      .subscribe((response: Blob) => {
        const blob = new Blob([response], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
        const link = document.createElement('a');
        link.href = window.URL.createObjectURL(blob);
        link.download = 'template.xlsx';
        link.click();
      });
    

    However, I get the following error:

    Response is not a Blob
    
  4. Tests Performed:

    • Tested the API in Insomnia and Postman, and the file is returned correctly.
    • Changed responseType to text, json, and other values, but the error persists.
    • Verified the response headers, and they seem correct.
  5. Lambda Configuration:
    The Lambda function is configured to return the file in Base64 with the following headers:

    const response = {
      statusCode: 200,
      isBase64Encoded: true,
      body: base64EncodedFile,
      headers: {
        "Content-Type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        "Content-Disposition": "attachment; filename=\"template.xlsx\"",
        "Access-Control-Allow-Origin": "*"
      }
    };
    return response;
    

Question:

How can I configure my Angular code to correctly consume this API that returns an Excel file in Base64? Is there anything I can adjust in the API Gateway or Lambda function configuration to solve this issue?


What I've Tried:


Additional Information:


Thanks:

Thank you in advance for any help or suggestions! 😊


Solution

  • According to your response example, the response is base64-encoded text, not a blob.

    body: base64EncodedFile
    
    this.http.post('https://my-api.com/suitability-produtos-templates', {}, { responseType: 'blob' })
    

    That means you are passing text here rather than bytes.

    const blob = new Blob([response], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
    

    Try instead to pick base64 (or commit to serving a raw file).

    const response = {
      statusCode: 200,
      isBase64Encoded: true,
      body: base64EncodedFile,
      headers: {
        "Content-Type": "text/plain",
        "Access-Control-Allow-Origin": "*"
      }
    };
    

    Then using this function to convert the base64 string to a downloadable file (by way of converting to bytes and a Blob).

    function downloadBase64File(base64: string, filename: string, mimeType: string) {
      const byteChars = atob(base64);
      const byteNumbers = new Uint8Array(byteChars.length);
      
      for (let i = 0; i < byteChars.length; i++) {
        byteNumbers[i] = byteChars.charCodeAt(i);
      }
      
      const blob = new Blob([byteNumbers], { type: mimeType });
      const url = URL.createObjectURL(blob);
      
      const a = document.createElement('a');
      a.href = url;
      a.download = filename;
      a.click();
      
      URL.revokeObjectURL(url);
    }
    

    The better solution would be to serve the raw file and not add the processing and 30% size overhead of base64, but you are already serving base64 so I used that.