- File needs to be downloaded at the frontend.
- Data of that file is being served by the backend.
1. Embed the link of the file to be downloaded on tag, and download the file in the new tab.
The above approach works fine for simpler use cases when the file being served is public and can be accessed by the whole world.
But what if the file is behind some kind authentication and can only be called via API by providing necessary authentication details (like bearer token in request authorization header).
This will result in error when downloading the file, and you’ll find the backend error shown on the UI.
Error while downloading file since authentication details were not provided
2. Call the API
To overcome the issue faced in approach one, we’ll have to access the file by calling the API. In the API request we can additionally provide necessary details to make the backend application aware that we have access to the requested file.
This is the approach we are going to discuss, i.e., call the API, get the data download this data as a file on the browser.
- On click of the button, call the download API for the file which needs to be downloaded as a BLOB.
- Create url out of the blob and store the object downloaded in the browser memory.
- Click the hidden anchor tag programatically which links to the above generated url.
- React + Typescript: for single page application
- Axios: for API calls.
- react-bootstrap + bootstrap: for ready to use components and styling.
- luxon: to deal with dates.
- Create a react + typescript boilerplate as mentioned in official react documentation (https://create-react-app.dev/docs/adding-typescript/)
npx create-react-app react-download-file-axios –template typescript
2. Install helper libraries
npm i axios @types/axios luxon @types/react bootstrap react-bootstrap
Let’s start coding
A simple reusable component for a button which can handle state for loading when calling the API.
- buttonState: Button can be in loading or a normal state (primary).
- onClick: on click handler function which needs to be called on click of button.
- label: text shown on the button
Reusable custom hook: useDownloadFile.ts
Let’s go through this function now.
The hook accepts various parameters:
An axios API called wrapped inside a function which contains API definition.
Function which is executed just before calling the API.
This function can be used as a pre hook to do any tasks which needs to be done before the API call is made.
Example: Disable button / change button state to loading.
Function which is executed after making the API call.
This function can be used as a post hook to do any tasks which needs to be done after the API call is made.
Example: Enable button / change button state to primary.
Function to be called when API has resulted in failure.
Error handling can be done over here.
Example: Show an alert to the user saying something has went wrong and the file is not downloaded.
Utilities exposed by the hook
- ref: ref which will be attached to the
<a />tag in the parent component.
- url: URL representing the data fetched from the API.
- name: name of the file which the user sees when downloading it on their system.
- download: function which needs to be invoked when file needs to be downloaded.
Flow of download function:
- Call the API. In case of any error,
onErrorfunction will be invoked to handle the error.
- Create a url which represents the downloaded data and store it in the state. This url is provided to
<a href... />.
- Generate the name of the file by which it will be downloaded in the browser. Store the same name in the state.
- Click the
<a />in the DOM to download the file.
- Destroy the generated url.
Component to download the file: downloadSampleCsvFileFinally let us stitch in all the pieces of code to download a sample csv file on click of a button.
There are two state variables to maintain state of the button, and show alert in case of error while calling API.
To the useDownloadHook custom hook various functions are passed:
- preDownloadFile: sets button state to loading.
- postDownloadFile: sets button state back to primary.
- onError: shows something went wrong alert.
- apiDefinition: axios get call to the API with responseType of blob type.
- getFileName: generates the file name based on current time.
Then the component returns the JSX:
- < a /> : hidden tag not visible to the user. Function download internally clicks this button after file is downloaded using refs.
- < button /> : button which the user clicks to download the required file.
Different Button States
3. < Alert /> : responsible for showing error message on the UI
Alert when calling API results in error.
<DownloadSampleCsv /> component to
Start the application & test the functionality
npm start / yarn start