Http POST works in Postman but not in Flutter

7,420

This is definitely a problem with the server. The two headers X-Reference-Id and X-Target-Environment are being handled case sensitively by the server (i.e. it is not in compliance with the RFC).

It's Dart's io.HttpClient that forces headers to lower case, so this affects package:http and package:dio which both rely on it. There's a request to allow the client to preserve the case of headers but it's coming slowly as it's a breaking change.

In the meantime, try using this fork of the client which preserves header case. https://pub.dev/packages/alt_http/

Share:
7,420
ama
Author by

ama

WIP

Updated on December 16, 2022

Comments

  • ama
    ama over 1 year

    I am trying to do a POST request on my flutter application using the Http package. I tested my request first on the Api sandbox website, and then in Postman. It works well there, but once in Flutter, I always get a 400 Bad Request.

    Here is my code in Flutter:

    import 'package:http/http.dart';
    import 'package:uuid/uuid.dart';
    import 'package:wave_app/env/secrets.dart';
    import 'package:wave_app/models/momo_token.dart';
    
        String url = "https://sandbox.momodeveloper.mtn.com/collection/v1_0/requesttopay";
        var uuid = Uuid();
        String requestId = uuid.v4();
        MomoToken token = await _createMomoNewTokenCollection();
    
        String auth = "Bearer " + token.accessToken;
    
        Map<String, String> headers = {
          "Authorization": auth,
          "X-Target-Environment": "sandbox",
          "X-Reference-Id": requestId,
          "Content-Type": "application/json",
          "Ocp-Apim-Subscription-Key": momoCollectionSubscriptionKey
        };
    
        String jsonBody = '{"amount": "5","currency": "EUR", "externalId": "123", "payer": {"partyIdType": "MSISDN","partyId": "46733123454"}, "payerMessage": "tripId-123456","payeeNote": "driverId-654321"}';
    
        Response response = await post(url, headers: headers, body: jsonBody);
        int statusCode = response.statusCode;
    
        print("STATUS CODE REQUEST TO PAY " + statusCode.toString());
        print(response.reasonPhrase.toString());
        print(response.body.toString());
    
        if (statusCode == 202) {
          return response.body.toString();
        } else {
          return null;
        }
      }

    The api doc is here: https://momodeveloper.mtn.com/docs/services/collection/operations/requesttopay-POST?

    And here is the code in curl of my Postman request (using the same variable above requestId, auth, momoCollectionSubscriptionKey)

    curl --request POST \
      --url https://sandbox.momodeveloper.mtn.com/collection/v1_0/requesttopay \
      --header 'Accept: */*' \
      --header 'Accept-Encoding: gzip, deflate' \
      --header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSMjU2In0.eyJjbGllbnRJZCI6IjFmY2MzMjBhLTM0NWQtMTFlYS04NTBkLTJlNzI4Y2U4ODEyNSIsImV4cGlyZXMiOiIyMDIwLTAxLTExVDE1OjU3OjE4Ljc3NyIsInNlc3Npb25JZCI6ImZmYzc1OGE2LTM2MWEtNDM4ZS1hYjE5LWQ1ZGQ4ZmU4ZjEyOSJ9.DeoJyU6Hb0he_or1XeBxW-6s-xwdtmi0cUrYjQe0Z796bIGvvT-VJ214JaZItG-CBQpgv7dHbLfXNqr8D05Q7U9XiOtpr8mtYWQlY-MseGIHAyxp1qBuQkwjmBYBlDxQOYYfzG9SZ8tGFUI1_k59LMNYIhDlXXKa68Ym1sylZ8wfWjGuHaKVzMEH25ubiBwCLev5IHPchuF3toVP99U-HC8t95E3zrEt9dHgzn0hnwvpB31wcsu_b3vb-YZ1idHgosPc2GmKFsDruX14VniKBicCsnGHqZAkSPXwaOR6SIn4JZEEwhAIj3Oe2H5dwxloiX5rzaApdkwEg6KSoBXk8A' \
      --header 'Cache-Control: no-cache' \
      --header 'Connection: keep-alive' \
      --header 'Content-Length: 194' \
      --header 'Content-Type: application/json' \
      --header 'Host: sandbox.momodeveloper.mtn.com' \
      --header 'Ocp-Apim-Subscription-Key: 281eb****************' \
      --header 'Postman-Token: ece19062-1f0b-4873-a3ed-1bd4ada8746a,528004b2-410d-4653-9909-5197a3dc95db' \
      --header 'User-Agent: PostmanRuntime/7.20.1' \
      --header 'X-Reference-Id: 062f8aad-f529-4d0a-804c-affb888c2b8b' \
      --header 'X-Target-Environment: sandbox' \
      --header 'cache-control: no-cache' \
      --data '{\r\n  "amount": "5",\r\n  "currency": "EUR",\r\n  "externalId": "123",\r\n  "payer": {\r\n    "partyIdType": "MSISDN",\r\n    "partyId": "46733123454"\r\n  },\r\n  "payerMessage": "hi",\r\n  "payeeNote": "hi"\r\n}'

    On postman and their website, I always get a 202 Accepted response. I am not sure, what I'm doing wrong here. Any help would be greatly appreciated!

    ------------ EDIT -------------------

    I also tried with HttpClient, here is the code, but still got 400 Bad Request

    HttpClient httpClient = new HttpClient();
        HttpClientRequest request = await httpClient.postUrl(Uri.parse(url));
    
        request.headers.set("Authorization", "Bearer " + token.accessToken);
        request.headers.set('content-type', 'application/json');
        request.headers.set("X-Target-Environment", "sandbox");
        request.headers.set("X-Reference-Id", requestId);
        request.headers.set("Ocp-Apim-Subscription-Key", momoCollectionSubscriptionKey);
    
        request.add(utf8.encode(jsonBody));
        HttpClientResponse response = await request.close();
    
        print("STATUS CODE " + response.statusCode.toString() + "   " + response.reasonPhrase);
        String reply = await response.transform(utf8.decoder).join();
        print("REPLY " + reply);
        httpClient.close();