0

$USD

$USD
TUTORIALS ESP32

ESP32 Arduino Tutorial 24. HTTP web server: Handling body data

DFRobot Jan 30 2019 2640

Introduction

In this tutorial we will learn how to handle the body of a HTTP POST request, sent to a HTTP web server running on the ESP32.

We will be using the Arduino core and the async HTTP web server libraries. Please consult the “Related posts” section at the end for more posts on the HTTP web server libraries.

Important: If you experience compilation problems similar to the ones mentioned in this GitHub issue, please make sure to update the AsyncTCP library to this version, accordingly to what is suggested here.

The AsyncTCP library is a dependency of the HTTP async web server libraries, which needs to be installed before using the framework, as indicated in this getting started post.

In order to update to the version of the AsyncTCP library that fixes the issue, simply go to the link and click the “Clone or Download” button. Choose the “Download ZIP option” and extract the downloaded folded. Rename it from “AsyncTCP-idf-update” to simply “AsyncTCP”.

Then, locate Arduino folders where you should have originally installed the AsyncTCP library and paste there the previously downloaded and renamed folder. When asked to replace the folder, choose accept. For security, you may make a copy of the previous version before replacing it, in case you need to rollback.

The tests were performed using a DFRobot’s ESP32 module integrated in a ESP32 development board.

If you prefer a video version of this tutorial, please check my YouTube channel below.

The code

We will start by including the WiFi.h and the ESPAsyncWebServer.h libraries, in order to be able to both connect the ESP32 to a WiFi network and then to setup the HTTP web server to listen to incoming requests.

To be able to connect to the network, we will need to have its credentials, namely the name of the network (SSID) and the password.

To finish the global variable declarations, we will also need an object of class AsyncWebServer, which exposes the methods that we will use to setup the server routes and make it listen to the incoming requests.

#include "WiFi.h"
#include "ESPAsyncWebServer.h"

const char* ssid = "yourNetworkName";
const char* password =  "yourNetworkPassword";

AsyncWebServer server(80);

Moving on to the Arduino setup function, we will open a serial connection and then we will connect the ESP32 to the WiFi network, printing the IP that is assigned to it when the connection procedure finishes.

Serial.begin(115200);

WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {
  delay(1000);
  Serial.println("Connecting to WiFi..");
}

Serial.println(WiFi.localIP());

Now we will take care of setting up a server route, which will receive the HTTP POST requests. To configure the route, we will use the on method of our AsyncWebServer object, like we did in many of the previous tutorials covering the HTTP web server framework for the ESP32.

As usual, we pass as first input a string with the name of the route, which we will call “/post“. As second input, we need to specify the HTTP methods that can be used on the route. Since we are only going to handle POST requests in this test, we will use the HTTP_POST enumerated value as second input of the on method.

Now, as third method, we need to pass a route handling function. Note that, in previous tutorials, it was in this function that we would implement all the logic associated with the reception of the request on that route.

Nonetheless, for this tutorial, our logic will depend on the body of the HTTP POST request, which we will not access in this function, but rather in a dedicated body handling function. Thus, we will still pass a C++ lambda function as we did before in previous tutorials (respecting the signature defined by the ArRequestHandlerFunction type), but we leave the body of this function empty.

Important: At the time of writing, we need to pass an empty handling function instead of NULL. If we pass NULL, the body handling function, which we will define later, will never execute.

As we can see in this header file, the on method is overloaded and it has a signature version that can receive two extra parameters. The fourth one is an upload handling function, that we will not need.

In this case, for this fourth argument, we can pass the value NULL rather than an function with an empty body. This will not cause any problems to te execution of the body handling function.

Finally, as fifth argument, we need to specify a body received handling function, which needs to respect the signature defined by the ArBodyHandlerFunction type (defined in this header file).

In order to respect the mentioned signature, our handling function should return void.

As first parameter, it receives a pointer to an object of class AsyncWebServerRequest. This is the same object that we have used in route handling functions in past tutorials to return back an answer to the client, and we can also use it in the body handling function for that same purpose.

As second argument, the function receives a pointer to an array of bytes, which correspond to the body of the request. As third argument, it receives the length of the mentioned array.

Important: The handling function also receives a fourth parameter named index in the function signature definition, and as fifth a parameter named total.

Although at the time of writing it is not clear in the documentation what is the purpose of these parameters, the example provided to the implementation of a body request handling function seems to indicate that the body may be received in chunks and these parameters are used to know the position of the chunk and the total number of bytes to be received for the whole request body.

Nonetheless, during my tests with, I haven’t yet used any body payload that was received in chunks and there’s most likely a minimum length that will split the body in chunks. In this GitHub issue, a user mentions that he has done tests with payloads up to 1.5KB and did not yet received a chunked response.

It’s important to clarify that the HTTP web server framework will take care of passing the parameters to our handling function whenever a HTTP POST request with a body is performed to our route. So, we only need to bind the handling function to the route once in our Arduino setup and we no longer need to call any function periodically. After the server starts, the framework will take care of everything under the hood and call our handling function when the body is received.

Note that, to keep the code more compact, we will declare the body handling function using the C++ lambda syntax.

server.on(
    "/post",
    HTTP_POST,
    [](AsyncWebServerRequest * request){},
    NULL,
    [](AsyncWebServerRequest * request, uint8_t *data, size_t len, size_t index, size_t total) {

      //Handling function implementation
  });

Our handling function implementation will be very simple. First, we will print all the received bytes of the body to the serial port in a loop. Since we know the length of the array of data we have received, we have a stopping condition for our loop.

for (size_t i = 0; i < len; i++) {
    Serial.write(data[i]);
}

Next, we will return back to the client a response to his request. For our simple example, we will just return an OK HTTP code (200). We do this by calling the send method on the AsyncWebServerRequest object pointer, passing as input the number of the HTTP response code.

request->send(200);

After concluding the declaration of our route, we need to call the begin method on our server object, so it starts listening to incoming HTTP requests.

server.begin();

The final source code can be seen below.

#include "WiFi.h"
#include "ESPAsyncWebServer.h"

const char* ssid = "yourNetworkName";
const char* password =  "yourNetworkPassword";

AsyncWebServer server(80);

void setup() {
  Serial.begin(115200);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }

  Serial.println(WiFi.localIP());

  server.on(
    "/post",
    HTTP_POST,
    [](AsyncWebServerRequest * request){},
    NULL,
    [](AsyncWebServerRequest * request, uint8_t *data, size_t len, size_t index, size_t total) {

      for (size_t i = 0; i < len; i++) {
        Serial.write(data[i]);
      }

      Serial.println();

      request->send(200);
  });

  server.begin();
}

void loop() {}

Testing the code

To test the code, first compile and upload it to your ESP32 using the Arduino IDE. Once the procedure finishes, open the serial monitor and copy the IP address that will get printed when the device connects to the WiFi network.

In order to make the POST request to the server, my recommendation is to use Postman, a very easy to use and free tool that allows to send HTTP requests.

After installing Postman, open it and, on the URL bar, type the following, changing #yourIp# by the IP address you have copied from the Arduino IDE serial monitor:

http://#yourIp#/post

Then, on the methods dropdown on the left of the URL bar, choose “POST“. Then, click on the “body” tab below the URL bar and, on the radio buttons below, choose “raw“.

A text editor will open. There you can specify your body content. I’m going to write a simple “Hello World” message, but you can put the content you want. Finally, click the “Send” button.

Figure 1 illustrates in more detail the user interface of Postman and the mentioned parts that need to be configured. Note that after sending the request, the ESP32 should return a 200 HTTP code (OK) as response, as also illustrated in figure 1, in green.

Postman application configured to send HTTP request with body to the ESP32 HTTP web server

Figure 1 – Postman with the request sent to the ESP32 and the response returned.

If you go back to the Arduino IDE serial monitor, you should see the body content sent by Postman, as illustrated in figure 2.

Output of the HTTP request body printed to the Arduino IDE serial monitor

Figure 2 – Output of the request body printed to the serial monitor.