dartdart-server

Dart server side: How to receive data from the Postman (form-data)?


I am using dart:io to create the server. I send the request from the Postman with form-data. I need to use form-data because my old API from another language uses it and the app uses it too.

At the moment. I am trying to get the data and files with this code:

Future main(List<String> arguments) async {
  HttpServer server = await HttpServer.bind('localhost', 8085);
  server.listen((HttpRequest request) async {
    String jsonString = await request.cast<List<int>>().transform(utf8.decoder).join();
    print("jsonString:\n$jsonString");
    await request.response.close();
  });
}

When I send the data and a file from the Postman with this below.

enter image description here

I will get the error below.

Unhandled exception:
FormatException: Unexpected extension byte (at offset 435)

If I don't send the file as image 1, I got this.

jsonString:
----------------------------166099235909119466948633
Content-Disposition: form-data; name="key 1"
Content-Type: application/json

value 1
----------------------------166099235909119466948633
Content-Disposition: form-data; name="key 2"

value 2
----------------------------166099235909119466948633--

I can't convert the above results to variables. I don't know how to do that. Has anyone an example for doing this or suggest any package to me? This is my first time creating a dart server.


Solution

  • I follow this. You can get the data and files from the request by using shelf_multipart (Other packages may be used in conjunction with this one and find more methods on GitHub).

    If you want to see results quickly that it can be done. Follow this below.

    I am using 3 packages including the shelf, shelf_router, and shelf_multipart packages.

    You need to add these packages to your pubspec.yaml. (You can copy and paste these into your pubspec.yaml.)

    dependencies:
      shelf: ^1.4.0
      shelf_router: ^1.1.3
      shelf_multipart: ^1.0.0
    

    Then copy my code and past it to your main.dart:

    import 'dart:convert';
    import 'package:shelf/shelf.dart';
    import 'package:shelf/shelf_io.dart' as shelf_io;
    import 'package:shelf_router/shelf_router.dart';
    import 'package:shelf_multipart/form_data.dart';
    import 'package:shelf_multipart/multipart.dart';
    
    Future main(List<String> arguments) async {
      final service = Service();
      final server = await shelf_io.serve(service.handler, 'localhost', 8085);
      print('Server running on localhost:${server.port}');
    }
    
    class Service {
      Handler get handler {
        final router = Router();
    
        router.post("/example", (Request request) async {
          if (request.isMultipart && request.isMultipartForm) {
            Map<String, dynamic>? data = await RequestConverter.formData(request);
            return data != null
                ? Response.ok("form-data: true, receive-data: true, data: $data")
                : Response.ok("form-data: true, receive-data: false");
          }
    
          return Response.ok("form-data: false");
        });
    
        router.all('/<ignored|.*>', (Request request) {
          return Response.notFound('Page not found');
        });
        return router;
      }
    }
    
    class RequestConverter {
      static Future<Map<String, dynamic>?> formData(Request request) async {
        try {
          Map<String, dynamic> data = {};
          Map<String, dynamic> files = {};
          final List<FormData> formDataList = await request.multipartFormData.toList();
          for (FormData formData in formDataList) {
            if (formData.filename == null) {
              String dataString = await formData.part.readString();
              data[formData.name] = Json.tryDecode(dataString) ?? dataString; //Postman doesn't send data as json
            } else if (formData.filename is String) {
              files[formData.name] = await formData.part.readBytes();
            }
          }
          return {"data": data, "files": files};
        } catch (e) {
          return null;
        }
      }
    }
    
    class Json {
      static String? tryEncode(data) {
        try {
          return jsonEncode(data);
        } catch (e) {
          return null;
        }
      }
    
      static dynamic tryDecode(data) {
        try {
          return jsonDecode(data);
        } catch (e) {
          return null;
        }
      }
    }
    

    After this, you can start your server in your terminal. For me I am using:

    dart run .\bin\main.dart
    

    Finally, open the Postman and paste http://localhost:8085/example to the URL field, select the POST method, and form-data. You can add the data into the KEY and VALUE fields. Then press send.

    This is my example in the Postman: enter image description here

    This solution work with http.MultipartRequest() from the Flutter app.