Uploading files fails with the new components

We are just unable to figure out how to use the new file components to upload files
The same request works via postman.

POST
FORM-DATA (yes I even added it to the headers manually just in case)

This worked just fine with the old component using .file

I checked and .file returns and object while .value[0] returns a base64 string

Hey @davidl!

It looks like the issue is that the metadata and base64 of the image is separated. The current workaround is to use something like this to re-assemble the two:

{{ {...fileButton1.files[0], "data": fileButton1.value[0] } }}

And pass that single object in for the file value. Would this work for your use case here?

Hi @victoria

I have the same issue.
The format you wrote doesn't work for me.
This is my API error: "The image field is required."

Hi @Soheil_Ebrahimi! Would you mind sharing a screenshot of your current query? And if you could also click into the field (where you're passing in the fileButton files and values) to bring up the little green preview box and share a screenshot, that would be super helpful.

Hi again @victoria! Thank you for your response. I set a wrong content-type for header! BTW thank you for the approach!

Oh awesome! So glad to hear that. My pleasure :raised_hands:t3:

Hi Victoria,
can you give the complete term for this workaround? I am new to retool and cannot re-engineer the correct object for this.
Michael

Hi Michael! That should be all you need - the ...(spread operator in Javascript) brings out the key value pairs from the files object and allows them to be joined with the data key. Is this not working for you?

Hi Victoria,
the term added to the "Attachments" property of a SMTP query is not working. When I hover over it I get several error messages:
"Expected an identifier and instead saw '...'"
"Missing semicolon"
"Expected '}' to match '{' from line 1 and instead saw ':'"

I tried to use a temporary state instead:

uploadedFile.setValue({...fileButton1.files[0], "data": fileButton1.value[0] })	;
query5.trigger();

where query5 is a smtp query with {{ uploadedFile.value }} in the Attachment(s) property. But this query is not successfull:

"Use File Picker to upload a file and ensure file is uploaded before query is fired".

Inspecting the uploadedFile shows

{
   value:
      { data: "some bin64 string",
        lastModified: 163876704321,
        name: "filename.pdf",
        size: 26649,
        type: "application/pdf"
      },
    id: "uploadedFile",
    pluginType: "State"
}

Would you mind sharing a screenshot of your current query?

He wanted to share this!

Thank you! :slightly_smiling_face:

And to double check, do you know if you're using the new file button or the older one? We can confirm via a screenshot of the right panel to show the file button properties (the newer button has a different set of customizable properties), or even better, your left panel, expanded out to show the data structure of your file button.

Do you know what file structure your resource is expecting from the Attachment field? General API file types expect the below format:

{

name:

size:

lastModified:

type:

data:

}

and you can make that happen by placing {{ {...fileButton1.files[0], "data": fileButton1.value[0] } }} directly in the field!

I'm using the workaround just fine {{ {...fileButton1.files[0], "data": fileButton1.value[0] } }}
can you let me know if this changes?

This should still be the proper structure to pass along a file object! How has it been working for you?

Hi @victoria - I am actually running into a similar issue with a Google Cloud Storage file upload.

I have a file button upload:

Which calls my query:

Here is the data shown in the preview (which all looks right):

However, after the upload completes, it shows in Google Cloud Storage as only 15B and is not the full size...

Most of the googling suggests using a javascript file input stream to stream it to the google cloud storage bucket but that doesnt seem possible from what I understand through retool.

Hi @mikalw! Interesting. So the upload connection is working, but it must not be uploading the right data. I just learned we have a bug around GCS + JSON uploads this morning, so perhaps this is related. For this bug, the workaround would be to manually define the content type as 'application/json' and stringifying the JSON data to be passed in.

Does this sound related at all? Do you know what data has been uploaded by any chance, aside from just the file size?

Hi @victoria, thanks for your reply! Looks like we are getting closer but are not quite there yet.

I changed my query to 'application/json' and stringifyed the data as you recommended:

The query runs successfully and I see the file in Firebase Storage (GCS behind the scenes). But, it looks like the PDF fails to load:

@victoria here is my dummy.pdf in case you want to test it out: https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf

That's perfect, thank you for sharing! I tested uploading just the binary of the PDF file (and not a proper PDF object), which can be grabbed using

{{fileButton2.value[0]}}

and it uploaded successfully!

Here's the generated media url:

https://storage.googleapis.com/download/storage/v1/b/retool-test-dad5c.appspot.com/o/pdf-test?generation=1646326358896465&alt=media

Let me know if that works for you!