# Handling file uploads and downloads

{% embed url="<https://www.youtube.com/watch?v=wI51DT6Ztmk>" %}
Upload and read a file
{% endembed %}

***

## **Stuck on Your Project? We've Got You Covered!**

Whether you're short on time or need coding expertise, our **Professional Services** team is here to help.

* Fast turnaround times
* Expert developers
* Affordable rates

[Click here to learn more!](https://blog.mern.ai/professional-services)

***

## Setting up Backend

### Upload File

1. Create a '`Blank Backend Function`' file in `main-features` folder and name it as '`upload`'.
2. Paste the below code in '`upload.server.tsx`'

{% code title="upload.server.tsx" %}

```tsx
import {
    createBackendFunction,
    createRequestContext,
    utils,
} from "@magicjs.dev/backend"

export default createBackendFunction(async function () {
    createRequestContext(this)
        .uploader()
        .onFile((info, file) => {
            // Will get the file information from the parameter info.
            utils.saveFileToUserUploads("/", `image.jpg`, file)
        })
})
```

{% endcode %}

* It calls the `uploader` method on the request context, which sets up functionality related to handling file uploads.
* The `onFile` method is called, which sets up an event handler for when a file is uploaded. It takes a callback function `(info, file)` as an argument.
  * `info` contains information about the uploaded file.
  * `file` contains the uploaded file itself.
  * It uses the `utils.saveFileToUserUploads` function to save the uploaded file to a specified location in the user's uploads directory.

This code defines a backend function that handles file uploads. It uses the `createRequestContext` function to create a request context, sets up an uploader, and defines an event handler for handling file uploads.

### Read File

1. Create a '`Blank Backend Function`' file and name it as '`getfile`'.
2. Paste the below code in '`getfile.server.tsx`'

{% code title="getfile.server.tsx" %}

```tsx
import { createBackendFunction, utils } from "@magicjs.dev/backend"

export default createBackendFunction(async function (fileName: string) {

    return utils.readFileFromUserUploads("/", fileName)

})
```

{% endcode %}

* The `readFileFromUserUploads` method from the `utils` module is called with two arguments:
  * `"/"`: This is the path to the user's upload folder.&#x20;
  * `fileName`: This is the name of the file that needs to be read from the specified upload folder.
* The function returns the result of the `readFileFromUserUploads` operation, which represents the content or data of the file being read.

## Integrate in UI

1. Create a '`Blank UI Component`' file in a feature.
2. Name the file '`upload`' and give a suitable path. We are assigning the path: '`/upload`'.
3. Paste the code given below in '`upload.tsx`'.

{% code title="upload.tsx" %}

```typescript
import React from "react"
import { createUploader, createSrc } from "@magicjs.dev/frontend"
import { Button, Input } from "antd"
import uploadServer from "./upload.server"
import getfileServer from "./getfile.server"

const fileSrc = createSrc(getfileServer)

export default function Component(props: any) {
    const { addFiles, upload, readyToUpload, uploadProgress, loading } =
        createUploader(uploadServer)
        
    return (
        <div>
            <Input
                type="file"
                onChange={(e) => {
                    addFiles(e.target.files)
                    // Adds selected files to the uploader instance
                }}
            />
            <Button
                onClick={() => upload()}
                disabled={loading === true || Boolean(readyToUpload) === false}
            >
                Upload: {uploadProgress}%
            </Button>

            <div>
                <img src={fileSrc.getLink("image.jpg")} alt="File Preview" />
            </div>
        </div>
    )
}
```

{% endcode %}

<details>

<summary>Expand for Tailwind styled code.</summary>

```typescript
import React from "react"
import { createUploader, createSrc } from "@magicjs.dev/frontend"
import uploadServer from "./upload.server"
import getfileServer from "./getfile.server"

const fileSrc = createSrc(getfileServer)

export default function Component(props: any) {
  const [isImageSelected, setIsImageSelected] = React.useState(false);
  const [imageName, setImageName] = React.useState('');
  const { addFiles, upload, readyToUpload, uploadProgress, loading } =
    createUploader(uploadServer)

  return (
    <div className="flex flex-row items-center justify-start h-screen gap-10 p-10">
      <div className="flex flex-col gap-3">
        <div className="flex items-center gap-3 w-[300px]">
          <button
            className="h-[35px] font-medium text-[13px] bg-[#FFFFFF] text-[#1C274C] px-4 rounded-[5px] border border-[#E3E3E3] hover:opacity-70 active:scale-95"
            onClick={() => {
              const fileInput = document.getElementById('fileInput');
              if (fileInput) {
                fileInput.click();
              }
            }}
          >
            Choose File
          </button>
          <div className="text-gray-600 text-sm" id="fileInputLabel">
            {isImageSelected ? imageName : `No file chosen yet`}
          </div>
        </div>
        <input
          type="file"
          id="fileInput"
          className="sr-only"
          onChange={(e: any) => {
            const selectedFile = e.target.files?.[0];
            if (selectedFile && selectedFile.name) {
              const fileName = selectedFile.name.length > 20
                ? selectedFile.name.slice(0, 20) + '...'
                : selectedFile.name;

              const fileInputLabel = document.getElementById('fileInputLabel');

              if (fileInputLabel) {
                fileInputLabel.innerText = fileName;
              }
              // Adds selected files to the uploader instance
              addFiles(e.target.files);
              setImageName(fileName)
              setIsImageSelected(true)
            }
          }}
        />
        <button
          className='w-fit text-[20px] text-white bg-violet-500 border border-[#BFBFBF] rounded-[10px] p-3 disabled:bg-violet-300 disabled:cursor-not-allowed hover:opacity-70 active:scale-95'
          onClick={() => upload()}
          disabled={loading === true || Boolean(readyToUpload) === false}
        >
          Upload: {uploadProgress}%
        </button>
      </div>
      <div>
        <img className="w-400" src={fileSrc.getLink("image.jpg")} alt="File Preview" />
      </div>
    </div>
  )
}
```

*The code may have significant modifications to enhance the styling of the input button.*

</details>

* It renders a file input (`Input`) and a button (`Button`) for file selection and upload, respectively.
* The `onChange` event of the file input adds selected files to the uploader instance using the `addFiles` function.
* The upload button is disabled if the `loading` state is `true` or `readyToUpload` is `false`.
* It displays upload progress using the `uploadProgress` state.
* It renders an image tag (`img`) with the source URL obtained from `fileSrc.getLink("image.jpg")`, displaying a preview of the uploaded file.

<figure><img src="/files/bd0CzfuJnd6rDRwp7a8c" alt=""><figcaption><p>Output - Preview of the uploaded image</p></figcaption></figure>

{% hint style="info" %}
Choose a file to upload and click on the button '`Upload`'. Refresh the page to view the uploaded file.
{% endhint %}

***

## **Ready to step into the role of a Product Owner?**

Dive into our comprehensive course designed to equip you with the skills and knowledge needed to excel. [Click here](https://university.mern.ai/) to embark on your journey towards becoming a proficient product owner and unlocking exciting career opportunities!

***


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://skyslit.gitbook.io/magicjs/basic-guide/handling-file-uploads-and-downloads.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
