Ad

Flutter Receives 422 Response From Fastapi When Posting A PNG File

I have created a working localhost API with FastAPI. The POST takes a PNG, does some image processing and returns a PNG as expected when I click the 'try it out' button in the FastAPI generated docs: successful localhost api call for png The curl post command shows as follows:

curl -X 'POST' \
  'http://localhost:8345/api/predict' \
  -H 'accept: application/json' \
  -H 'Content-Type: multipart/form-data' \
  -F '[email protected]_img.png;type=image/png'

The image File is successfully retrieved from the image picker library. (Where the image1 object has been initialized as File image1; in the app page's class.

Future getImage() async {
    var imageTmp = await ImagePicker.pickImage(source: ImageSource.gallery);
    setState(() {
      image1 = imageTmp;
      print('Image Path $image1');
    });
  }

I tried to emulate the API call with the below function in Flutter.

  doUpload() {
    /*
    curl -X 'POST' \
  'http://192.168.178.26:8345/api/predict' \
  -H 'accept: application/json' \
  -H 'Content-Type: multipart/form-data' \
  -F '[email protected]_img.png;type=image/png'

     */
    var request = http.MultipartRequest(
      'POST',
      Uri.parse("http://<my locally hosted ip>:8345/api/predict"),
    );
    Map<String, String> headers = {"Content-type": "multipart/form-data"};
    request.files.add(
      http.MultipartFile(
        'image',
        image1.readAsBytes().asStream(),
        image1.lengthSync(),
        filename: 'filename',
        contentType: MediaType('image', 'png'),
      ),
    );
    request.headers.addAll(headers);
    print("request: " + request.toString());
    request.send().then((value) => print(value.statusCode));
  }

When I run the doUpload() function, a POST is successfully sent to the localhost API, but it returns a 422 error 'unprocessable entity'. What I tried:

  • I tried to set the image type in doUpload to jpg, jpeg, but I keep getting a 422 error.
  • I tried looking up where the image_picker is supposed to store the temporary file to see if it's stored correctly, but when I look at the generated filepath, I don't see the actual file and tmp folder: filepath: File: '/data/user/0/<my package name>/cache/image_picker3300408791299772729jpg'

looking at my local UI filepath, I see: enter image description here

It shows no folder named cache, so I can't inspect it like this. However, the image picker saves it with a jpg at the end (not .jpg, is this normal?)

Ad

Answer

To mimic that curl command exactly, use this: (I've used the convenience constructor for simplicity)

  final request = http.MultipartRequest(
    'POST',
    Uri.parse('http://<my locally hosted ip>:8345/api/predict'),
  );

  request.files.add(
    await http.MultipartFile.fromPath(
      'file', // NOTE - this value must match the 'file=' at the start of -F
      image1.path,
      contentType: MediaType('image', 'png'),
    ),
  );

  final response = await http.Response.fromStream(await request.send());

  print(response.body);
Ad
source: stackoverflow.com
Ad