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,
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.
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:
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.
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.