React + custom hook + typescript to download a file through API
Wondering how to download files on UI by calling an API behind authentication?
- 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 <a/> 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 athentication and can only be called via API by providing necessary authentication details (like bearer token in request authorisation 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.
File gets downloaded after clicking on the button with the provided file name
- 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
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
Button component
A simple reusable component for a button which can handle state for loading when calling the API.
Accepts three props:
1. buttonState: Button can be in loading or a normal state (primary)
2. onClick: on click handler function which needs to be called on click of button
3. label: text shown on the button
Reusable custom hook: useDownloadFile.ts
Purpose of this code is to abstract the download file functionality into a reusable custom hook so that it can be reused across many pages.
Always better to follow the famous Don’t Repeat Yourself (DRY) programming principle.
Let’s go through this function now.
DownloadFileProps
The hook accepts various parameters:
1. apiDefinition
An axios API called wrapped inside a function which contains API definition.
2. preDownloading
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 the API call is made.
Example: Disable button / change button state to loading.
3. postDownloading
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 the API call is made.
Example: Enable button / change button state to primary.
4. onError
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
1. ref: ref which will be attached to the <a />
tag in the parent component.
2. url: URL representing the data fetched from the API.
3. name: name of the file which the user sees when downloading it on their system.
4. download: function which needs to be invoked when file needs to be downloaded.
Flow of download function:
1. Invoke preDownloading
function.
2. Call the API. In case of any error, onError
function will be invoked to handle the error.
3. Create a url which represents the downloaded data and store it in the state. This url is provided to <a href... />
.
4. Generate the name of the file by which it will be downloaded in the browser. Store the same name in the state.
5. Click the <a />
in the DOM to download the file.
6. Invoke postDownloading
function.
7. Destroy the generated url.
Component to download the file: downloadSampleCsvFile
Finally let us stitch in all the pieces of code to download a sample csv file on click of a button.
This file is pretty straightforward.
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:
1. preDownloadFile: sets button state to loading.
2. postDownloadFile: sets button state back to primary.
3. onError: shows something went wrong alert.
4. apiDefinition: axios get call to the API with responseType of blob type.
5. getFileName: generates the file name based on current time.
Then the component returns the JSX:
1. <a />
: hidden tag not visible to the user. Function download
internally clicks this button after file is downloaded using refs.
2. <Button />
: button which the user clicks to download the required file.
This article is also posted under the author’s medium account, here.
We are Hiring!!
At Tech Prescient, we are always looking for good and passionate folks, who love challenges and like to own problems. If you think you are a change-maker who is hungry to create, develop, and influence; Don’t Wait!
Apply Now: https://cutshort.io/company/tech-prescient-Sdo5bhiP