Flutter receives 422 response from Fastapi when posting a PNG file

435

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);
Share:
435
DaReal
Author by

DaReal

Updated on December 21, 2022

Comments

  • DaReal
    DaReal over 1 year

    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 'file=@test_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 'file=@test_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?)

  • DaReal
    DaReal over 2 years
    This worked perfectly, thanks a bunch! It returned INFO: <my local phone ipv4> - "POST /api/predict HTTP/1.1" 200 OK I only had additionally change the function to doUpload() async { due to your await. Which is probably for the better anyway :)
  • DaReal
    DaReal over 2 years
    Also thanks for explaining what made it work, with the file comment