2

I'm using the file_picker package for flutter https://pub.dev/packages/file_picker I have read many times that because you can’t access paths on web browsers, you need to use the bytes property, e.g.

FilePickerResult result = await FilePicker.platform.pickFiles();

if(result != null) {
   var path = print(result.files.single.path); // this will return null
   var bytes = print(result.files.singe.bytes); // this will return a Uint8List of bytes
} else {
   // User canceled the picker
}

But I have to upload the images my users select from their devices via the web (so for all types of devices) to my Stripe Connect API in order for them to have a validated identity_document when they register. The bytes Uint8List will throw an error from firebase, here is my code:

export const uploadIdentityFront = async (uid: any, identityFront: any) => {
    
  const fp = fs.readFileSync(identityFront);
    
  const frontIdentity = await stripe.files.create({
        file: {
            data: fp,
            name: 'identityFront.jpg',
            type: 'application/octet-stream',
        },
        purpose: 'identity_document',
    });

    await updateId(uid, { frontIdentityFileId: frontIdentity.id })
    return frontIdentity;

}

The error thrown:

[firebase_functions/unknown] TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string or an instance of Buffer or URL. Received an instance of Array

I will need to send stripe an image document via the file system's readFileSync property in order to do this, but with Flutter Web not being able to print the path for the image chosen by the user, I am stuck on how to resolve this issue

James 666
  • 1,560
  • 1
  • 15
  • 27

2 Answers2

1

I use this code to send bytes to my server, which uses stream to send. You can use http package to send streams.

var request = http.MultipartRequest(
  'POST',
  Uri.parse('_url'),
);


request.files.add(
  http.MultipartFile.fromBytes(
    'identityFront', //name of field which you receive in api
    bytes, // bytes
    filename: 'identityFront.jpg', // optional name
    //contentType: content, optional media Type
 ));

 request.fields.addEntries([
     MapEntry('uid', 'uid_value_in_String_Type'),
 ]);
 
await request.send();
Reza M
  • 544
  • 3
  • 10
  • Tried it out and set the url to my api, but alas no luck - nothing changes in my dashboard. It's a pain because all of this could be solved if I could generate the path of my image from the device of the user – James 666 Jun 07 '21 at 16:35
  • Unfortunately, There is no way to get path of file in flutter web. Your fault is here `const fp = fs.readFileSync(identityFront);`. `identityFront` is not path of file. It's `byte stream`. You should read it another way. https://stackoverflow.com/questions/25345237/how-to-upload-and-read-a-file-with-nodejs-express/39985359 https://stackoverflow.com/questions/60222660/how-to-read-text-file-from-post-with-express-uploadfile – Reza M Jun 08 '21 at 03:31
1

I finally solved it. For anyone trying to upload a file to Stripe via flutter web, don't create a fs.readFileSync in your backend server side code. Instead, remove it and upload a file like this:

export const uploadIdentityFront = async (uid: any, identityFront: any) => {
        
  const frontIdentity = await stripe.files.create({
        file: {
            data: identityFront,
            name: 'identityFront.jpg',
            type: 'image/jpg',
        },
        purpose: 'identity_document',
    });

    await updateId(uid, { frontIdentityFileId: frontIdentity.id })
    return frontIdentity;

}

This way, you can upload the file via the file_picker package and uploading it as a picker.file.first.bytes. But don't wrap it in a string - send it just like this as a callable function in firebase functions:

await uploadFrontPassport.call(
   <dynamic, dynamic>{'identityFront':picked.files.first.bytes}
);
James 666
  • 1,560
  • 1
  • 15
  • 27