Flutter upload file through rest api endpoint

Issue

I have a flutter app that interacts with a server through a REST api where it can fetch and display information. It can also send text information to the server. I want to add functionality of sending pdf files and images to the server but I dont know how to achieve that. Here is the code for selecting files

 @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Another Attempt'),
        centerTitle: true,
      ),
      body: Container(
        alignment: Alignment.topCenter,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            MaterialButton(
              onPressed: () async {
                FilePickerResult result =
                    await FilePicker.platform.pickFiles(allowMultiple: true);

                if (result != null) {
                  List<File> files =
                      result.paths.map((path) => File(path)).toList();
                } else {
                  // User canceled the picker
                }
              },
              child: Text('Upload multiple files'),
              color: Colors.blueAccent,
            ),
            SizedBox(height: 10.0),
            MaterialButton(
              onPressed: () async {
                FilePickerResult result = await FilePicker.platform.pickFiles();

                if (result != null) {
                  File file = File(result.files.single.path);
                } else {
                  // User canceled the picker
                }
              },
              child: Text('Upload single file'),
              color: Colors.blueAccent,
            ),
            SizedBox(height: 10.0),
            MaterialButton(
              onPressed: () {
                _submitData();
              },
              child: Text('Upload single file'),
              color: Colors.blueAccent,
            ),
          ],
        ),
      ),
    );
  }

 void _submitData() async {
    setState(() {});

    var data = {
      'image': file,
      'pdf': files,
     };


    try {
      var res = await Network().postData(data, '/convert-customer');
      var body = json.decode(res.body);
      if (res.statusCode == 200 || res.statusCode == 201) {
        print(res.statusCode);
        print(body);
      } else {}
    } on TimeoutException catch (_) {
      print("Your connection has timedout");
      _formKey.currentState.reset();
    } on SocketException catch (_) {
      print("You are not connected to internet");
      _formKey.currentState.reset();
    }

    setState(() {
      _isLoading = false;
    });
  }

Here is the code for sending data to the server


  final String _baseUrl = 'http://106.20.34.127/trial/api/v1';

  var token;

  _getToken() async {
    SharedPreferences localStorage = await SharedPreferences.getInstance();
    token = jsonDecode(localStorage.getString('token'))['token'];
  }
  postData(data, apiUrl) async {
    try {
      var _finalUrl = _baseUrl + apiUrl;
      Uri fullUrl = Uri.parse(_finalUrl);
      await _getToken();
      print(fullUrl);
      return await http.post(fullUrl,
          body: jsonEncode(data), headers: _setHeaders());
    } catch (e) {
      print(e);
    }
  }

How do I go about it.

Solution

Use http.MultipartRequest instead of http.post for files. Usually, the body of a POST request is made of textual key-value pairs. With a multipart POST request, you can also include files with binary content (images, various documents, etc.), in addition to the regular text values.

import 'package:http/http.dart' as http;

var req = http.MultipartRequest('POST', Uri.parse(url));

This req object has a member Map called fields for textual values and a List called files to which you can add MultipartFiles.

The most important element of this whole thing is the MultipartFile. It can be constructed in a few ways:

  1. The default MultipartFile(key, stream, length) constructor, which
    you can use if you need to create the file from a Stream of bytes of
    which we know the length.

  2. The MultipartFile.fromBytes(key, bytes) factory method, which
    attaches a file obtained from a List of bytes.

  3. The MultipartFile.fromString(key, string) factory method, which attaches a text file containing the string passed to it.

  4. The MultipartFile.fromPath(key, path) factory method, which attaches the file found at the given path.

Example: Using MultipartFile.fromPath() you could write a function like the following

  (String filename, String url) async {
  var request = http.MultipartRequest('POST', Uri.parse(url));
  request.files.add(
    await http.MultipartFile.fromPath(
      'pdf',
      filename
    )
  );
  var res = await request.send();
}

or you can simply use this multipart_request plugin available on pub.dev

Answered By – aiwithab

Answer Checked By – Pedro (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *