S3 Uploader
Let's say you want to upload a file to one of your S3 buckets, using POST.
Your API has a protected endpoint that returns the necessary S3 upload params. Maybe it uses Boto to generate a presigned upload URL.
A successful request to this endpoint returns something like this:
{
"fields": {
"AWSAccessKeyId": "AKIAJSQUO7ORWYVCSV6Q",
"acl": "public-read",
"key": "files/89789486-d94a-4251-a42d-18af752ab7d2-test.txt",
"policy": "eyJleHBpcmF0aW9uIjogIjIwMTgtMTAtMzBUMjM6MTk6NDdaIiwgImNvbmRpdGlvbnMiOiBbeyJhY2wiOiAicHVibGljLXJlYWQifSwgWyJjb250ZW50LWxlbmd0aC1yYW5nZSIsIDEwLCAzMTQ1NzI4MF0sIHsiYnVja2V0IjogImJlYW10ZWNoLWZpbGUifSwgeyJrZXkiOiAiY29tcGFueS8zLzg5Nzg5NDg2LWQ5NGEtNDI1MS1hNDJkLTE4YWY3NTJhYjdkMi10ZXN0LnR4dCJ9XX0=",
"signature": "L7r3KBtyOXjUKy31g42JTYb1sio="
},
"fileUrl": "https://my-bucket.s3.amazonaws.com/files/89789486-d94a-4251-a42d-18af752ab7d2-test.txt",
"uploadUrl": "https://my-bucket.s3.amazonaws.com/"
}
fields
has everything you need to authenticate with your S3 bucket, but you need to add them to the request sent by RDU. It turns out this is super easy.
const getUploadParams = async ({ meta: { name } }) => {
const { fields, uploadUrl, fileUrl } = await myApiService.getPresignedUploadParams(name)
return { fields, meta: { fileUrl }, url: uploadUrl }
}
That's it. If myApiService.getPresignedUploadParams
succeeds, you return uploadUrl
as url
. You also decide to merge fileUrl
into your file's meta so you can use it later. RDU takes care of the rest, including appending the fields to the FormData
instance used in the XMLHttpRequest
.
Let's say myApiService.getPresignedUploadParams
fails and returns {}
. In this case uploadUrl
and hence url
are undefined. RDU abandons the upload and changes the file's status to 'error_upload_params'
. At this point you might show the user an error message, and the user might remove the file or restart the upload.
S3 using PUT instead of POST
Uploading a file to S3 using PUT works differently than using POST.
Basically, if you use PUT, you can't wrap your file in a FormData
instance. In this case, body
must be set to file
, and the fields
in the POST example are all encoded in the query string of the uploadUrl
. getUploadParams
would look a little different:
const getUploadParams = async ({ file, meta: { name } }) => {
const { uploadUrl, fileUrl } = await myApiService.getPresignedUploadParams(name)
return { body: file, meta: { fileUrl }, url: uploadUrl }
}