CodeDon
CodeDon

Reputation: 77

Sending XFile image to API using MultipartFile - Flutter

I have an application that caters for web, android and ios. I have implemented the packages below

https://pub.dev/packages/image_picker/example


Tasks:

  1. User needs to select multiple images (When debugging thru android, i sometimes receive websocket connection expection, and application exits without any error message. Bonus if youre able to provide some insights to this issue as well)

  2. Clicks submit to upload the images (XFile) to API

class UserAttachments {
  List<XFile>? attachments = [];
  int userID = 0;
}

Future<String> submitImage(UserAttachments ua) async {
  http.MultipartRequest request =
      new http.MultipartRequest("POST", Uri.parse(kAttachmentsURI));

  Map<String, String> headers = {"Content-Type": "application/json"};

  ua.attachments!.forEach((element) async {
    var bytes = element.readAsBytes();
    request.files.add(new http.MultipartFile.fromBytes('file', await bytes));
  });

  request.headers.addAll(headers);
  request.fields['userID'] = '23';

  http.StreamedResponse responseAttachmentSTR = await request.send();

  print(responseAttachmentSTR.statusCode);
  return "SENT"; // + "  - Respomse:  " + map.toString();
}

Above code doesn't seem to work. Any solutions that cater for web/android/ios?

Upvotes: 0

Views: 3595

Answers (2)

SHANG
SHANG

Reputation: 74

This is typically used when uploading files, as shown in the following examples:

import 'dart:io';
import 'package:dio/dio.dart';
import 'package:image_picker/image_picker.dart';

Future<void> uploadXFile(XFile xfile) async {
  Dio dio = Dio();
  String url = 'https://example.com/upload'; // Replace with your API endpoint

  try {
    // Convert XFile to MultipartFile
    MultipartFile multipartFile = await MultipartFile.fromFile(
      xfile.path,
      filename: xfile.name, // Optional: Custom file name
    );

    // Create FormData
    FormData formData = FormData.fromMap({
      'file': multipartFile,
    });

    // Send POST request
    Response response = await dio.post(
      url,
      data: formData,
      options: Options(
        headers: {
          "Content-Type": "multipart/form-data", // Required header
        },
      ),
    );

    print("Response: ${response.data}");
  } catch (e) {
    print("Upload failed: $e");
  }
}

Upvotes: 0

C10ver
C10ver

Reputation: 1

You can't use async on forEach, because that will just return an array of promises and won't wait for them. To fix this, you can use a for loop for asynchronous functions.

for(var i = 0; i < ua.attachments!.length; i++) {
  var element = ua.attachments[i];
  var bytes = element.readAsBytes();
  request.files.add(new http.MultipartFile.fromBytes('file', await bytes));
}

And you can optimize this code using Future.wait

Future<String> submitImage(UserAttachments ua) async {
      http.MultipartRequest request =
          new http.MultipartRequest("POST", Uri.parse(kAttachmentsURI));
    
      Map<String, String> headers = {"Content-Type": "application/json"};
    
      var bytes = await Future.wait(ua.attachments!.map((el) => el.readAsBytes()));
      request.files.addAll(bytes.map((b) => new http.MultipartFile.fromBytes('file', b)));
    
      request.headers.addAll(headers);
      request.fields['userID'] = '23';
    
      http.StreamedResponse responseAttachmentSTR = await request.send();
    
      print(responseAttachmentSTR.statusCode);
      return "SENT";
}

Upvotes: 0

Related Questions