Unable to get video file for S3 upload. (using Expo Camera)

1.1k Views Asked by At

I have been stuck with trying to upload a video to S3 for a while and was hoping to get some pointers. Currently, what I've read and was told is that we need to send an actual file to S3 and not the url (which we might do if we were sending it to the backend before aws).

I am trying to do this by

const getBlob = async (fileURi) => {
    console.log('THIS IS IT', fileURi);
    const resp = await fetch(fileURi);
    const videoBody = await resp.blob();
    console.log(videoBody);
};
getBlob(video.uri);

The problem I am having is I am unable to actually get the video file. When I stop recording a video with await camera.stopRecording(); what I get in return is

Object {
  "uri": "file:///path/20DD0E08-11CA-423D-B83D-BD5ED40DFB25.mov",
}

Is there a recommended approach in order to successfully get the actual file in order to send it to S3 through the client?

The way I am trying to currently send the video which doesn't work is:

    const formData = new FormData();
    formData.append('file', video.uri);

    await fetch(url, {
        method: 'POST',
        body: formData,
        headers: {
            'Content-Type': 'multipart/form-data'
        }

url: refers to the presignedUrl we get in return from aws.

P.S - Sending to the server through a fetch call does work but I noticed this approach also leave the User waiting for 10+ seconds since I need to send the video to the server then wait for it to finish uploading in AWS.

Thank you for all the help.

2

There are 2 best solutions below

2
On

If I understand correctly you know how to upload file to your own server, but you want to send it directly to S3.

In that case I would suggest to use presigned URLs. https://docs.aws.amazon.com/AmazonS3/latest/dev/PresignedUrlUploadObject.html

You can generate presigned URL on your backend, it is basically regular URL pointing to S3 file and some key values. You need to send those values to mobile app and do the same fetch call you are already using, but replace url with the one generated on backend and add all key-values to FormData.

Example for node backend would look like this

import AWS from 'aws-sdk';
...

const client = new AWS.S3(config);
...
    const presignedUrl = client.createPresignedPost({
      Bucket: 'example-bucket-name',
      Fields: { key: 'example-file-name' },
    });

and in mobile app you would

    const form = new FormData();
    Object.keys(presignedUrl.fields).forEach(key => {
       form.append(key, presignedUrl.fields[key]);
    })
    form.append('file', fileToUpload);

    await fetch(presignedUrl.url, {
        method: 'POST',
        body: form,
        headers: {
            'Content-Type': 'multipart/form-data'
        }
    })
0
On

My solutions. Please review the sample application. https://github.com/expo/examples/tree/master/with-aws-storage-upload

const response = await fetch(video.uri);
        const blob = await response.blob();
        const params = {
            Bucket: myBucket,
            Metadata: {
                long: long.toString(),
                lat: lat.toString(),
                size: videoSize.toString()
            },
            Key: myKey,
            Body: blob
        };