Support Topics Documentation Slack YouTube Blog

Error 400 while trying to upload a file

I am currently attempting to upload the file to Backendless storage using the REST API but I get an error 400 while trying to do so.

I use React Native and Fetch API to do the job. OS is Android 10.

Here is the code that handles the upload:

  const handleUpload = async () => {
    const url = `https://api.backendless.com/${keys.APPLICATION_ID}/${
      keys.REST_API_KEY
    }/files/${remotePath}/${file.name}?overwrite=true`;
    const body = new FormData();
    body.append(file);
    body.append('user-token', user.userToken);
    console.log(await fetch(url, {method: 'POST', body}));
  };

file contains the URI, type, and name as supplied by react-native-document-picker library.

Return log:

 {"_bodyBlob": {"_data": {"__collector": [Object], "blobId": "xxxxxx", "offset": 0, "size": 108}}, "_bodyInit": {"_data": {"__collector": [Object], "blobId": "xxxxxx", "offset": 0, "size": 108}}, "headers": {"map": {"access-control-allow-methods": "POST, GET, OPTIONS, PUT, DELETE, PATCH", "access-control-allow-origin": "*", "connection": "keep-alive", "content-length": "108", "content-type": "application/json", "date": "Mon, 29 Jun 2020 15:20:02 GMT", "server": "nginx", "strict-transport-security": "max-age=31536000; preload"}}, "ok": false, "status": 400, "statusText": undefined, "type": "default", "url": "https://api.backendless.com/CD8B0A40-0E0D-070F-FF5D-2E6AC915F900/xxxxxx/files/user/20200629_161148.jpg?overwrite=true"}

When you do this:

body.append('user-token', user.userToken);

will add the user token value as an HTTP header?

Wil the Content-Type header be set to multipart/form-data?

Finally, will the request body be formatted per the multipart/form-data requirements?

Mark

Fixed silly mistake in regards to the headers, now they are defined properly. And FormData() is supposed to format things in accordance to multipart/form-data requirements. The request still doesn’t seem to work, though.

  const handleUpload = async () => {
    const url = `https://api.backendless.com/${keys.APPLICATION_ID}/${
      keys.REST_API_KEY
    }/files/${remotePath}/${file.name}?overwrite=true`;
    const body = new FormData();
    body.append(file);
    console.log(file.type);
    console.log(
      await fetch(url, {
        method: 'POST',
        headers: {
          'Content-Type': 'multipart/form-data',
          'user-token': user.userToken,
        },
        body,
      }),
    );
  };

It appears that the issue might be related to URI of the file. This seems like something I have to solve on my part atm.

It looks like the following line doesn’t materialize/format the body of the request per the requirements of the multipart/form-data:

As an alternative, you can use this call and put into the body a base64 encoded value of the file contents.

Yes, I just found out that it’s basically the specifics of the way Android handles files.

As per the doc for the picker thing:

uri :
The URI representing the document picked by the user. On iOS this will be a file:// URI for a temporary file in your app’s container. On Android this will be a content:// URI for a document provided by a DocumentProvider that must be accessed with a ContentResolver.

The URI is incorrect for the request and has to be resolved specifically, and I have to do it in any case.

Turns out Fetch API supports Blobs, which theoretically should be enough to upload a file. Instead, though, fetch now returns TypeError: Network request failed.

Here is the updated code:

 const handleUpload = async () => {
    const url = `https://api.backendless.com/${keys.APPLICATION_ID}/${
      keys.REST_API_KEY
    }/files/${remotePath}/${file.name}?overwrite=true`;
    const data = new FormData();
    data.append('file', file);
    console.log(file);
    try {
      console.log(
        await fetch(url, {
          method: 'POST',
          headers: {
            'Content-Type': 'multipart/form-data',
            'user-token': user.userToken,
          },
          body: data,
        }),
      );
    } catch (e) {
      console.log(e);
    }
  };

and this is what gets passed into body:

{
 "name": "20200629_225454.jpg",
 "type": "image/jpeg", 
 "uri": "content://pl.solidexplorer2.files/-548115613/storage/emulated/0/Pictures/Twitter/20200629_225454.jpg"
}

The URI is correct, I checked by pasting it into a browser.

The API you’re using requires that the payload body be in the multipart/form-data format. Setting the Content-Type to multipart/form-data is not sufficient. The payload must be formatted according to the requirements as well. You can see an example of it here:

A complete specification is available here:
https://www.ietf.org/rfc/rfc2388.txt

The body you sent is a plain JSON and doesn’t meet the requirements. Tis is the reason why you’re getting the error.

Regards,
Mark

I did not send the plain JSON. Body is FormData, which contains the entry with name ‘file’ and value being the object with the data that I mentioned. This, according to the FormData API specification, should have the "multipart/form-data" format.

Could you share what the request body looks like?