0

I am trying to send files to server with flutter but it return this error:

Unhandled Exception: type 'List<File>' is not a subtype of type 'String' in type cast

Code

I've commented code below for better understanding

late List<File> newDoc = [];

// Select files
ElevatedButton(
    onPressed: () async {
        FilePickerResult? result = await FilePicker.platform.pickFiles(
            allowMultiple: true
            type: FileType.custom,
            allowedExtensions: ['jpg', 'pdf', 'doc', 'docx', 'ppt', 'pptx'],
        );
        if(result != null) {
            // Not sure if I should only get file path or complete data (this was in package documentation)
            List<File> files = result.paths.map((path) => File(path!)).toList();
            newDoc = files;
        } else {
            // User canceled the picker
        }
    },
    child: Text('Select Files'),
),

SizedBox(height: 15.0),

// Send files to server
ElevatedButton(
    onPressed: () async {

        //save
        var response = await http.post(
            Uri.parse('https://example.come/upload/${args.id}'),
            body: {
                'documents': newDoc,  // send array of my selected files to server
            },
            headers: {
                HttpHeaders.authorizationHeader: '$userToken',
                HttpHeaders.acceptHeader: 'application/json'
            },
        );

        print('request::: $response');


        // if (response.statusCode == 200) {
        //   .....
        // } else {
        //   .....
        // }
        //save

    },
    child: Text('Save'),
),

Any suggestions?

Update

I've changed my http request to code below but my server receives empty body (the request does not send my files to backend)

var request = http.MultipartRequest('POST', uri);
request.headers['authorization'] = '$userToken';
request.headers['acceptHeader'] = 'application/json';
newDoc.map((k) async {
    request.files.add(await http.MultipartFile.fromPath(
    'documents', k.path
    ));
});
var response = await request.send();
var response2 = await http.Response.fromStream(response);
print('request::: ${response2.statusCode}');
print('request::: ${response2.body}'); // return as []
mafortis
  • 6,750
  • 23
  • 130
  • 288

2 Answers2

0

You have to use MultipartRequest to upload files. For example:

var uri = Uri.parse('https://example.com/create');
var request = http.MultipartRequest('POST', uri)
  ..fields['user'] = 'nweiz@google.com'
  ..files.add(await http.MultipartFile.fromPath(
      'package', 'build/package.tar.gz',
      contentType: MediaType('application', 'x-tar')));
var response = await request.send();
if (response.statusCode == 200) print('Uploaded!');

So for you it is like that:

final request = net.MultipartRequest("post", Uri.parse("https://example.come/upload/${args.id}"));
for (final file in files) {
  request.files.add(await MultipartFile.fromPath(file.uri.pathSegments.last, file.path));
}
request.headers[HttpHeaders.authorizationHeader] = '$userToken';
request.headers[HttpHeaders.acceptHeader] = 'application/json';

final response = await request.send();

file.uri.pathSegments.last is a file name.

Autocrab
  • 3,474
  • 1
  • 15
  • 15
  • can you explain it a bit? what are `..fields`? what's `package`? it's a bit confusing to me. – mafortis Jun 21 '21 at 05:32
  • fields are some String data, if you don't want to send any addition data with files, then just remove fields line. package is just a key, all request data sends as key:value, so value is your file, key is just a key for server. For example you can write like "file1", "file2", etc – Autocrab Jun 21 '21 at 05:40
  • yeah but it gives me `The argument type 'List' can't be assigned to the parameter type 'String'` on `..files.add(await http.MultipartFile.fromPath( 'documents', newDoc ));` – mafortis Jun 21 '21 at 05:43
  • Thank you but `file.uri.pathSegments.last` I am trying to send multiple files is `last` only get 1 file? – mafortis Jun 21 '21 at 05:58
  • Please see my update based on your answer. – mafortis Jun 21 '21 at 06:15
0

Your post call should look like this

var response = await http.post(
    Uri.parse('https://example.come/upload/${args.id}'),
    body: {
        'documents': newDoc.map((e) => e.path).toList().join(', '),
    },
    headers: {
        HttpHeaders.authorizationHeader: '$userToken',
        HttpHeaders.acceptHeader: 'application/json'
    },
);

The newDoc variable is List of Files, so convert the List of files to list of Strings (paths) using newDoc.map((e) => e.path).toList().join(', ')

Shrijan Regmi
  • 450
  • 5
  • 10
  • it says `Unhandled Exception: type 'List' is not a subtype of type 'String' in type cast` – mafortis Jun 21 '21 at 06:14
  • try using newDoc.map((e) => e.path).toList().join(', '); – Shrijan Regmi Jun 21 '21 at 06:16
  • ok it does get them but do you think i should send my files as byte instead of path? my backend seems like does not recognize files by path?! – mafortis Jun 21 '21 at 06:21
  • I think after choosing the files from the file picker, you should upload the files to some cloud storage and then get the url from there and then save those urls to your backend. I am not actually a backend guy but I use firebase and I am doing the same there. Choose file using file picker and upload it to Firebase Storage and then send the url provided by firebase to the backend. – Shrijan Regmi Jun 21 '21 at 06:25
  • No that doesn't make sense, i just need to upload files in one place not 2, usually with kotlin I convert my files to base64 but in flutter it's my first attempt so I'm not sure how to. – mafortis Jun 21 '21 at 06:28
  • In that case you should see => https://stackoverflow.com/questions/64803104/how-to-get-base64-of-a-file-in-flutter. – Shrijan Regmi Jun 21 '21 at 06:31
  • However your initial issue ```Unhandled Exception: type 'List' is not a subtype of type 'String' in type cast``` is solved I guess ? If that's the case then you could mark this answer as accepted. Thanks – Shrijan Regmi Jun 21 '21 at 06:32
  • yes the error is gone now but my question is not solved yet `How to send files in flutter` I still unable to send files. – mafortis Jun 21 '21 at 06:40