Skip to content
Advertisement

Convert ByteArray response from API to a File in Typescript and save it

There are already few questions like the one I am asking and I tried those approaches but they didn’t work for me, maybe I am missing something and hence I am asking a new question.

I am calling an API in my typescript application, the API returns me an object which has a field containing the byte array representation of a file. Here’s how the response model looks

{
"fileName": "Pokemon.xlsx",
"fileData":"this is the byte array representation of the file",
"fileContent":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
}

In my typescript component I am calling the API and converting the JSON response into a response interface, this given code is what I referenced from other links

this.pokemonService.getExcel(REQUEST_OBJECT).subscribe((response) => {
      if (response) {
        const bytes = new Uint8Array(Buffer.from(response.fileData));
        const fileBlob = new Blob([bytes], { type: response.contentType });
        if (fileBlob.size > 0) {
          const link = document.createElement('a');
          link.href = window.URL.createObjectURL(file);
          link.download = `${response.fileName}`;
          link.click();
        }
      } else {
        //show error
      }
    });

given is the response interface that I cast the response to

export interface PokemonResponse {
  fileData: ArrayBuffer;
  fileName: string;
  contentType: string;
}

The issue with the above code is that when I open the excel it shows that the file is corrupted,

enter image description here

I also tried converting the fileBlob in the above code to a File object using the below code but still the same result, the downloaded file when opened with excel shows as corrupted.

const file = new File([bytes], response.fileName, { type: response.contentType  });

One thing I notice is that the ArrayBuffer contains a string representation (base64 is what I am guessing) of the file whereas the API is returning an array of bytes.

I tried to call the API directly using a C# console application and in the console app, it works as expected, the excel file is created and I can open and view the data without any corrupt file alert.

enter image description here

I feel like I am close to the solution but I am missing something here with regards to ArrayBuffer. Please suggest.

EDIT: Adding screenshot of the byte comparison of C# console app vs typescript app

Console app:

enter image description here

and here’s a presentation of the byte I get in the typescript application, note that I am printing the bytes variable shown in the code above which is a Uint8Array,

on observing both the byte representation it seems that the bytes are not in the same sequence, I think the Uint8Array conversion could be disturbing the sequence in typescript.

enter image description here

Advertisement

Answer

After spending some time I was able to resolve the issue.

I found that we have to explicitly mention the type of data the browser is supposed to parse and return, so before returning the response from the service in angular, I updated the content type with the following code

contentType: `data:${response.contentType};base64,`

Please note that contentType is a property of the PokemonResponse interface as shown above.

once I did this, the file was downloaded successfully. I assumed that this was already done by the browser but I was wrong.

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement