POST a camera image to your API with Flutter and Dio.

May, 01 2020

Dio is an HTTP client for flutter which is a useful way of sending form data to your back-end API. In this case, we're using form data to send an image from the phone camera to be processed on our backend.

To reference the official documentation for Dio and Image Picker as you go along.

Start a clean flutter project and install the following packages via pubspec.yaml (double check official docs for latest versions):

dio: ^3.0.9 image_picker: ^0.6.5+3

On the very top of your main.dart file add the required imports:

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

Now, using the template app, let’s gut the _incrementCounter function and replace it with our own routine. We want to open up the camera and send the picture off to our server. Rename declaration and call of _incrementCounter to _choose and delete the original contents as shown below. Notice that _choose is now an async function. We want to make sure we’re waiting for the data to return from the server before moving on.

void _choose() async { } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ ], ), ), floatingActionButton: FloatingActionButton( onPressed: () async { _choose(); }, tooltip: 'Increment', child: Icon(Icons.add), ), ); }

Now let’s update _choose to take a picture and assign that picture to a File type variable — this will require the dart:io import.

void _choose() async { File file; file = await ImagePicker.pickImage( source: ImageSource.camera, ); if (file != null) { haveImg = true; futureImg = _upload(file); setState(() {}); } }

Notice the call to _upload(). Let’s fill that in next. Make sure to assign a variable for the end point of the call. This is the URL where your API request will be made. In my case, I am running a local server so my end point is http://10.0.2.2:8000/analyze

final String endPoint = 'http://10.0.2.2:8000/analyze'; void _upload(File file) async { String fileName = file.path.split('/').last; print(fileName); FormData data = FormData.fromMap({ "file": await MultipartFile.fromFile( file.path, filename: fileName, ), }); Dio dio = new Dio(); dio.post(endPoint, data: data).then((response) { var jsonResponse = jsonDecode(response.toString()); var testData = jsonResponse['histogram_counts'].cast<double>(); var averageGrindSize = jsonResponse['average_particle_size']; }).catchError((error) => print(error)); }

Here is where the actual form data is populated and posted. This requires the use of the dart:convert import to parse the json response. Here you may need to change the code based on what your response looks like after posting the image. My response contains a list: histogram_counts, and a string: average_particle_size. Now clicking the floating “+” button will prompt the camera to open and post the image to your local server.

Now go do some cool machine learning stuff on the back-end! Checkout the full code for this tutorial on github.