Electronic – arduino – HTTP Post error using ESP8266 from Arduino

arduinoesp8266

Using Arduino on an STM32F103C Blue Pill to drive an ESP8266 ESP-01 as shown below, and this tutorial: Arduino Forum

Arduino Forum

I am attempting to do an HTTP POST with the following code:

String ssid = "MySSID";
String password = "MyPassword";
String server = "192.168.1.134"; // IP hosting API (Flask w/ Python)
String uri = "/api/create/current/"; // API Route
String payload = "?outlet_id=1&voltage=2&vrms=3&amps_rms=4"; // Sample sensor payload

void httppost() {
  Serial2.println("AT+CIPSTART=\"TCP\",\"" + server + "\",80"); //start a TCP connection.
  if (Serial2.find("OK")) {
    Serial.println("TCP connection ready");
  }
  delay(1000);
  String postRequest =
    "POST " + uri + " HTTP/1.0\r\n" +
    "Host: " + server + "\r\n" +
    "Accept: *" + "/" + "*\r\n" +
    "Content-Length: " + payload.length() + "\r\n" +
    "Content-Type: application/json\r\n" +
    "\r\n" + payload;
  String sendCmd = "AT+CIPSEND="; //determine the number of characters to be sent.
  Serial2.print(sendCmd);
  Serial2.println(postRequest.length());
  delay(5000);

  if (Serial2.find(">")) {
    Serial.println("Sending..");
    Serial2.print(postRequest);

    if (Serial2.find("SEND OK")) {
      Serial.println("Packet sent");

      while (Serial2.available()) {
        String tmpResp = Serial2.readString();
        Serial.println(tmpResp);
      }
      // close the connection
      Serial2.println("AT+CIPCLOSE");
    }
  }

The post request is failing on the server-side with the following error:

Unexpected Error: malformed JSON in post request, check key/value pair at:

Nothing is else contained the error message or Flask server logs to indicate how/why the JSON is malformed. Using Postman, I'm able to perform a successful post with the following:

192.168.1.134/api/create/current/?outlet_id=1&voltage=2&vrms=3&amps_rms=4

Does anyone see anything obvious? FWIW, using the Blue Pill to power the ESP8266, or alternatively using an external power source produce the same results. It seems to be a syntactic problem but I'm not seeing it. Any help is much appreciated!

Best Answer

You are mixing up two different ways of sending information to a server.

When you use postman with the URL

192.168.1.134/api/create/current/?outlet_id=1&voltage=2&vrms=3&amps_rms=4

You are not actually sending any useful information in the body, but rather sending all of the data as URL parameters.

In contrast, your embedded code:

String uri = "/api/create/current/"; // API Route
String payload = "?outlet_id=1&voltage=2&vrms=3&amps_rms=4"; // Sample sensor payload

attempts to supply the "payload" in the message body.

But the problem is that your payload is not encoded as json, but rather still encoded as a series of URL parameters.

You should either add that "payload" string onto the end of the URL and not send it in the body.

Or else, if your server supports it, encode the payload as proper json, probably something like:

{"outlet_id": 1, "voltage": 2, "vrms": 3, "amps_rms": 4}

Note that if you want to put this as a constant into a C/C++ program, you'll have to escape the quotes, for (brief) example:

String payload = "{\"outlet_id\": 1}";

Also should you have any json values beyond numbers and true/false/null those would need their own quotes, eg

{"mode": "test"}

Ultimately this is an everyday RESTful API question more suited to Stackoverflow and not an embedded or EE question at all, though needing to be able to work with these kinds of things isn't uncommon in the age of IoT.