Example of JSON REST API on ESP32
JSON is a good standard for data exchange. It can be useful to dialog with an ESP32 calling it with a JSON API, and getting its responses in JSON as well.
Here is one way to do it.
It has been developed with Visual Code and Platform.io plugin and based on https://github.com/me-no-dev/ESPAsyncWebServer library.
Create the API
Start a blank main.cpp file, and add these following lines.
Import libraries:
#include <Arduino.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include "AsyncJson.h"
#include "ArduinoJson.h"
Start the local server on port 80:
AsyncWebServer server(80);
Set the current network Wifi access. The two defaults values have to be replaced by real ones:
const char *ssid = "NameOfNetwork";
const char *password = "SecurityPassword";
Create a route for not found pages:
void notFound(AsyncWebServerRequest *request)
{
request->send(404, "application/json", "{\"message\":\"Not found\"}");
}
Start the setup by enabling the serial and start Wifi connection:
void setup()
{
Serial.begin(9600);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.waitForConnectResult() != WL_CONNECTED)
{
Serial.printf("WiFi Failed!\n");
}
Once connected, display the ESP32 IP address, it will be used to send request:
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
Create a simple GET route on /. The response is a JSON in a string:
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(200, "application/json", "{\"message\":\"Welcome\"}");
});
Create a GET route with params on /get-message. The response is a JSON object converted in a string:
server.on("/get-message", HTTP_GET, [](AsyncWebServerRequest *request) {
StaticJsonDocument<100> data;
if (request->hasParam("message"))
{
data["message"] = request->getParam("message")->value();
}
else {
data["message"] = "No message parameter";
}
String response;
serializeJson(data, response);
request->send(200, "application/json", response);
});
Create a POST route receiving JSON data in parameters. Data has to be converted depending on the JSON object or array type. The response is the JSON object sent, converted in a string:
AsyncCallbackJsonWebHandler *handler = new AsyncCallbackJsonWebHandler("/post-message", [](AsyncWebServerRequest *request, JsonVariant &json) {
StaticJsonDocument<200> data;
if (json.is<JsonArray>())
{
data = json.as<JsonArray>();
}
else if (json.is<JsonObject>())
{
data = json.as<JsonObject>();
}
String response;
serializeJson(data, response);
request->send(200, "application/json", response);
Serial.println(response);
});
server.addHandler(handler);
Add a handler for not existing routes:
server.onNotFound(notFound);
Start the server and close the init method:
server.begin();
}
Add the loop method for future use:
void loop()
{}
The code can now be uploaded to the ESP32. When started it should display the following message from serial monitoring:
IP Address: xxx.xxx.xxx.xxx.xxx
With xxx.xxx.xxx.xxx the current IP address of the ESP32.
Full code
#include <Arduino.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include "AsyncJson.h"
#include "ArduinoJson.h"
AsyncWebServer server(80);
const char *ssid = "NameOfNetwork";
const char *password = "SecurityPassword";
void notFound(AsyncWebServerRequest *request)
{
request->send(404, "application/json", "{\"message\":\"Not found\"}");
}
void setup()
{
Serial.begin(9600);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.waitForConnectResult() != WL_CONNECTED)
{
Serial.printf("WiFi Failed!\n");
}
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
request->send(200, "application/json", "{\"message\":\"Welcome\"}");
});
server.on("/get-message", HTTP_GET, [](AsyncWebServerRequest *request) {
StaticJsonDocument<100> data;
if (request->hasParam("message"))
{
data["message"] = request->getParam("message")->value();
}
else
{
data["message"] = "No message parameter";
}
String response;
serializeJson(data, response);
request->send(200, "application/json", response);
});
AsyncCallbackJsonWebHandler *handler = new AsyncCallbackJsonWebHandler("/post-message", [](AsyncWebServerRequest *request, JsonVariant &json) {
StaticJsonDocument<200> data;
if (json.is<JsonArray>())
{
data = json.as<JsonArray>();
}
else if (json.is<JsonObject>())
{
data = json.as<JsonObject>();
}
String response;
serializeJson(data, response);
request->send(200, "application/json", response);
Serial.println(response);
});
server.addHandler(handler);server.onNotFound(notFound);
server.begin();
}void loop()
{
}
Testing
When started, the ESP32 should display its IP address, for example.
IP Address: 192.168.4.8
This IP address is used to make the request. Here is curl commands to test the ESP32 API.
Test / route
curl -i -X GET http://192.168.4.8/
Should return:
HTTP/1.1 200 OK
Content-Length: 21
Content-Type: application/json
Connection: close
Accept-Ranges: none{"message":"Welcome"}
Test /get-message route with a param
curl -i -X GET http://192.168.4.8/get-message?message=HelloServer
Should return:
HTTP/1.1 200 OK
Content-Length: 25
Content-Type: application/json
Connection: close
Accept-Ranges: none{"message":"HelloServer"}
Test /post-message route with data
curl -i -d '{"message":"My sample data"}' -H "Content-Type: application/json" -X POST http://192.168.4.8/post-message
Should return:
HTTP/1.1 200 OK
Content-Length: 28
Content-Type: application/json
Connection: close
Accept-Ranges: none{"message":"My sample data"}
Conclusion
The ESP32 can now be queried with GET requests and JSON POST requests and responds with JSON data.