Hey everyone,
We are trying to upload images via a put request using s3 presigned put urls.
We are not sure how to properly bind to the new Blob
method to get the file into the body of this request.
So far this is what we are using to acquire the actual file:
module FileReader = {
type fileReader
type file = {"name": string, "lastModified": int, "size": int, "type__": string}
@new external createFileReader: unit => fileReader = "FileReader"
@bs.send
external readAsDataURL: (fileReader, file) => unit = "readAsDataURL"
let onload: (fileReader, string => unit) => unit = %raw(`
function (reader, cb) {
reader.onload = function (e) {
cb(e.target.result);
}
}
`)
}
let file = ReactEvent.Form.target(event)["files"][0]
if file["size"] / 1024 / 1024 < 10 {
let reader = FileReader.createFileReader()
FileReader.onload(reader, url => {
setImageUrl(_ => url->Some) // Local preview
})
FileReader.readAsDataURL(reader, file)
//TODO: fetch put to s3 presigned url with file blolb
} else {
Js.log("Please choose an image less than 10 mb")
}
Javascript equivalent:
const fileBlob = new Blob([file], { type: file.type })
await fetch(data.shopAssetPresignUrl.url, {
method: 'PUT',
headers: { 'Content-Type': fileBlob.type },
body: fileBlob,
})
Thanks!
(Playground) How about:
module File = {
type t
type type_
@get
external type_: t => type_ = "type"
}
module Blob = {
type t
type type_
@new
external make: (array<File.t>, {"type": File.type_}) => t = "Blob"
@get
external type_: t => type_ = "type"
let make = file => make([file], {"type": file->File.type_})
}
type response
@scope("window") @val
external fetch: (
string,
{
"method": [
| #PUT
| #GET
| #POST
| #DELETE
],
"headers": 't,
"body": Blob.t,
},
) => response = "fetch"
let upload = (url, file) => {
let blob = file->Blob.make
fetch(
url,
{
"method": #PUT,
"headers": {
"Content-Type": blob->Blob.type_,
},
"body": blob,
},
)
}
Which compiles to:
// Generated by ReScript, PLEASE EDIT WITH CARE
var $$File = {};
function make(file) {
return new Blob([file], {
type: file.type
});
}
var $$Blob$1 = {
make: make
};
function upload(url, file) {
var blob = make(file);
return window.fetch(url, {
method: 'PUT',
headers: {
'Content-Type': blob.type
},
body: blob
});
}
export { $$File, $$Blob$1 as $$Blob, upload };
/* No side effect */
1 Like
A File
is already Blob
, so you don’t need new Blob
. Just put the file
that you have, in the fetch request body. Assuming you’re using bs-fetch, here’s an example: https://github.com/reasonml-community/bs-fetch/blob/934389964e1005d4e37911c8324a6aeb7ce0a1b0/examples/reason_examples.re#L50
You can adapt that to put the file in the formdata object being uploaded using https://github.com/reasonml-community/bs-fetch/blob/934389964e1005d4e37911c8324a6aeb7ce0a1b0/src/Fetch.mli#L267
1 Like
Thanks so much @yawaramin and @oliverfencott - I ended figuring this out with a pretty simplistic implementation.
The main method I was missing was was from bs-fetch
- All I really needed was the:
Fetch.BodyInit.makeWithBlob
Typically we always json stringify the body. With this helper we were able to proceed 
Thanks again!
2 Likes