[SOLVED] Upload single image from axios to FastAPI: "Expected UploadFile, received: <class 'str'>"

Issue

I try to upload an image from my react-admin app to FastAPI using axios. The ImageInput component returns a File object which I cast to a Blob and try to upload using axios.
The API client I am using has been generated by orval.

The response I receive after sending the POST:

{
    "detail":[
        {
            "loc":[
                "body",
                "file"
            ],
            "msg":"Expected UploadFile, received: <class 'str'>",
            "type":"value_error"
        }
    ]
}

axios request function:

/**
 * @summary Create Image
 */
export const createImage = (
  bodyCreateImageImagesPost: BodyCreateImageImagesPost,
  options?: AxiosRequestConfig
): Promise<AxiosResponse<Image>> => {
  const formData = new FormData();
  formData.append(
    "classified_id",
    bodyCreateImageImagesPost.classified_id.toString()
  );
  formData.append("file", bodyCreateImageImagesPost.file);

  return axios.post(`/images`, formData, options);
};

axios request headers:

POST /images HTTP/1.1
Host: localhost:8000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:96.0) Gecko/20100101 Firefox/96.0
Accept: application/json, text/plain, */*
Accept-Language: pl,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Authorization: bearer xxx
Content-Type: multipart/form-data; boundary=---------------------------41197619542060894471320873154
Content-Length: 305
Origin: http://localhost:3000
DNT: 1
Connection: keep-alive
Referer: http://localhost:3000/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
Sec-GPC: 1

Request data object:

{
  "classified_id": 2,
  "file": {
    "rawFile": {...},
    "src": "blob:http://localhost:3000/9826efb4-875d-42f9-9554-49a6b13204be",
    "name": "Screenshot_2019-10-16-18-04-03.png"
  }
}

FastAPI endpoint:

def create_image(
    classified_id: int = Form(...),
    file: UploadFile = File(...),
    db: Session = Depends(get_db),
    user: User = Security(manager, scopes=["images_create"]),
) -> Any:
    # ...

In the "Network" section of the developer tools in a browser, it shows the file field as [object Object] but I guess that’s just a problem with no string representation of the Blob?

When I try to upload an image through the Swagger UI, it works as expected and the curl request looks like this:

curl -X 'POST' \
  'http://localhost:8000/images' \
  -H 'accept: application/json' \
  -H 'content-length: 3099363' \
  -H 'Authorization: Bearer xxx' \
  -H 'Content-Type: multipart/form-data' \
  -F 'classified_id=2' \
  -F 'file=@Screenshot_2019-10-16-18-04-03.png;type=image/png'

Any ideas what is wrong in here? How should the proper axios request look like?

Solution

Use as follows (change the URL endpoint’s name, as well as the "Accept" header, to the ones you are using):

<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script type="text/javascript">
function uploadFile() {
    var formData = new FormData();
    var fileInput = document.getElementById('fileInput');
    if (fileInput.files[0]) {
        formData.append("classified_id", 2);
        formData.append("file", fileInput.files[0]);
        axios({
                method: 'post',
                url: '/upload',
                data: formData,
                headers: {
                    'Accept': 'application/json',
                    'Content-Type': 'multipart/form-data'
                },
            })
            .then(function(response) {
                console.log(response);
            })
            .catch(function(response) {
                console.error(response);
            });
    }
}
</script>
 <input type="file" id="fileInput" name="file"><br>
 <input type="button" value="submit" onclick="uploadFile()">

Answered By – Chris

Answer Checked By – Cary Denson (BugsFixing Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *