Skip to main content
๐Ÿ‘€ Interested in the latest enterprise backend features of refine? ๐Ÿ‘‰ Join now and get early access!
Version: 4.xx.xx

Multipart Upload

We will demonstrate how to perform a multipart upload with refine.

Let's start with the creation form first.

Create Formโ€‹

Let's add the image field to the post creation form.

pages/posts/create.tsx
import {
useApiUrl,
} from "@refinedev/core";
import {
getValueFromEvent,
Create,
useForm,
} from "@refinedev/antd";
import {
Upload,
Form,
Input,
} from "antd";

export const PostCreate: React.FC = () => {
const { formProps, saveButtonProps } = useForm<IPost>();

const apiUrl = useApiUrl();

return (
<Create saveButtonProps={saveButtonProps}>
<Form {...formProps} layout="vertical">
<Form.Item
label="Title"
name="title"
rules={[
{
required: true,
},
]}
>
<Input />
</Form.Item>
<Form.Item label="Image">
<Form.Item
name="image"
valuePropName="fileList"
getValueFromEvent={getValueFromEvent}
noStyle
>
<Upload.Dragger
name="file"
action={`${apiUrl}/media/upload`}
listType="picture"
maxCount={5}
multiple
>
<p className="ant-upload-text">
Drag & drop a file in this area
</p>
</Upload.Dragger>
</Form.Item>
</Form.Item>
</Form>
</Create>
);
};

interface IPost {
id: number;
title: string;
image: [
{
uid: string;
name: string;
url: string;
status: "error" | "success" | "done" | "uploading" | "removed";
},
];
}

TIP

We can reach the API URL by using the useApiUrl hook.

It will look like this.

localhost:5173

We currently require an upload endpoint that accepts multipart uploads. This address should be passed into the action property of the Upload component.

[POST] https://api.fake-rest.refine.dev/media/upload
{
"file": "binary"
}
CAUTION

This end-point should be Content-type: multipart/form-data and Form Data: file: binary.

This end-point should respond similarly.

[POST] https://api.fake-rest.refine.dev/media/upload
{
"url": "https://example.com/uploaded-file.jpeg"
}
CAUTION

We have to use the getValueFromEvent method to convert the uploaded files to Antd UploadFile object.

This data is sent to the API when the form is submitted.

[POST] https://api.fake-rest.refine.dev/posts
{
"title": "Test",
"image": [
{
"uid": "rc-upload-1620630541327-7",
"name": "greg-bulla-6RD0mcpY8f8-unsplash.jpg",
"url": "https://refine.ams3.digitaloceanspaces.com/78c82c0b2203e670d77372f4c20fc0e2",
"type": "image/jpeg",
"size": 70922,
"percent": 100,
"status": "done"
}
]
}
CAUTION

The following datas are required for the Antd Upload component and all should be saved.

PropertyDescription
uidUnique id
nameFile Name
urlDownload URL
statuserror, success, done, uploading, removed

Edit Formโ€‹

Let's add the image field to the post editing form.

pages/posts/edit.tsx
import {
useApiUrl,
} from "@refinedev/core";
import {
getValueFromEvent,
Edit,
useForm,
} from "@refinedev/antd";
import {
Upload,
Form,
Input,
} from "antd";

export const PostEdit: React.FC = () => {
const { formProps, saveButtonProps } = useForm<IPost>();

const apiUrl = useApiUrl();

return (
<Edit saveButtonProps={saveButtonProps}>
<Form {...formProps} layout="vertical">
<Form.Item
label="Title"
name="title"
rules={[
{
required: true,
},
]}
>
<Input />
</Form.Item>
<Form.Item label="Image">
<Form.Item
name="image"
valuePropName="fileList"
getValueFromEvent={getValueFromEvent}
noStyle
>
<Upload.Dragger
name="file"
action={`${apiUrl}/media/upload`}
listType="picture"
maxCount={5}
multiple
>
<p className="ant-upload-text">
Drag & drop a file in this area
</p>
</Upload.Dragger>
</Form.Item>
</Form.Item>
</Form>
</Edit>
);
};
localhost:5173

The request, like the one below, is sent for the edit form.

[GET] https://api.fake-rest.refine.dev/posts/1
{
"id": 1,
"title": "Test",
"image": [
{
"uid": "rc-upload-1620630541327-7",
"name": "greg-bulla-6RD0mcpY8f8-unsplash.jpg",
"url": "https://refine.ams3.digitaloceanspaces.com/78c82c0b2203e670d77372f4c20fc0e2",
"type": "image/jpeg",
"size": 70922,
"percent": 100,
"status": "done"
}
]
}

This data is sent to the API when form is submitted.

[PUT] https://api.fake-rest.refine.dev/posts/1
{
"title": "Test",
"image": [
{
"uid": "rc-upload-1620630541327-7",
"name": "greg-bulla-6RD0mcpY8f8-unsplash.jpg",
"url": "https://refine.ams3.digitaloceanspaces.com/78c82c0b2203e670d77372f4c20fc0e2",
"type": "image/jpeg",
"size": 70922,
"percent": 100,
"status": "done"
}
]
}

Uploading Stateโ€‹

You may want to disable the "Save" button in the form while the upload is going on. To do this, you can use the useFileUploadState hook.

pages/posts/create.tsx
import { useApiUrl } from "@refinedev/core";
import {
getValueFromEvent,
useFileUploadState,
Create,
useForm,
} from "@refinedev/antd";
import { Upload, Form, Input } from "antd";

export const PostCreate: React.FC = () => {
const { formProps, saveButtonProps } = useForm<IPost>();

const { isLoading, onChange } = useFileUploadState();

const apiUrl = useApiUrl();

return (
<Create
saveButtonProps={{
...saveButtonProps,
disabled: isLoading,
}}
>
<Form {...formProps} layout="vertical">
<Form.Item
label="Title"
name="title"
rules={[
{
required: true,
},
]}
>
<Input />
</Form.Item>
<Form.Item label="Image">
<Form.Item
name="image"
valuePropName="fileList"
getValueFromEvent={getValueFromEvent}
noStyle
>
<Upload.Dragger
name="file"
action={`${apiUrl}/media/upload`}
listType="picture"
maxCount={5}
multiple
onChange={onChange}
>
<p className="ant-upload-text">
Drag & drop a file in this area
</p>
</Upload.Dragger>
</Form.Item>
</Form.Item>
</Form>
</Create>
);
};

Exampleโ€‹

Run on your local
npm create refine-app@latest -- --example upload-antd-multipart