In the previous articles we explained the verb GET in detail, but when you want to create something you have to (can you?) use the verb POST.
For example if you want create an element like add a new room so you want start manage additional data, you must do a POST.
You can send data via POST with many formats, but the standard one is the JSON format.
The structure of the sketch is the same of the other, but you must set the correct verb:
server.on(F("/setRoom"), HTTP_POST, setRoom);
And you can grab the content passed in the body with this command:
String postBody = server.arg("plain");
twhen you have recovered the content, then obviously you have to pars it. (Refer to the article “Manage JSON file with Arduino and esp8266“)
DynamicJsonDocument doc(512);
DeserializationError error = deserializeJson(doc, postBody);
JsonObject postObj = doc.as<JsonObject>();
The complete sketch is
For esp32 you must only change this include
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
to
#include <WiFi.h>
#include <WebServer.h>
#include <ESPmDNS.h>
/*
* Json parametric POST REST request with ArduinoJSON library
* by Mischianti Renzo <https://mischianti.org>
*
* https://mischianti.org/
*
*/
#include "Arduino.h"
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <ArduinoJson.h>
const char* ssid = "<YOUR-SSID>";
const char* password = "<YOUR-PASSWD>";
ESP8266WebServer server(80);
// Serving Hello world
void setRoom() {
String postBody = server.arg("plain");
Serial.println(postBody);
DynamicJsonDocument doc(512);
DeserializationError error = deserializeJson(doc, postBody);
if (error) {
// if the file didn't open, print an error:
Serial.print(F("Error parsing JSON "));
Serial.println(error.c_str());
String msg = error.c_str();
server.send(400, F("text/html"),
"Error in parsin json body! <br>" + msg);
} else {
JsonObject postObj = doc.as<JsonObject>();
Serial.print(F("HTTP Method: "));
Serial.println(server.method());
if (server.method() == HTTP_POST) {
if (postObj.containsKey("name") && postObj.containsKey("type")) {
Serial.println(F("done."));
// Here store data or doing operation
// Create the response
// To get the status of the result you can get the http status so
// this part can be unusefully
DynamicJsonDocument doc(512);
doc["status"] = "OK";
Serial.print(F("Stream..."));
String buf;
serializeJson(doc, buf);
server.send(201, F("application/json"), buf);
Serial.print(F("done."));
}else {
DynamicJsonDocument doc(512);
doc["status"] = "KO";
doc["message"] = F("No data found, or incorrect!");
Serial.print(F("Stream..."));
String buf;
serializeJson(doc, buf);
server.send(400, F("application/json"), buf);
Serial.print(F("done."));
}
}
}
}
// Define routing
void restServerRouting() {
server.on("/", HTTP_GET, []() {
server.send(200, F("text/html"),
F("Welcome to the REST Web Server"));
});
// handle post request
server.on(F("/setRoom"), HTTP_POST, setRoom);
}
// Manage not found URL
void handleNotFound() {
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++) {
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
}
void setup(void) {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// Activate mDNS this is used to be able to connect to the server
// with local DNS hostmane esp8266.local
if (MDNS.begin("esp8266")) {
Serial.println("MDNS responder started");
}
// Set server routing
restServerRouting();
// Set not found response
server.onNotFound(handleNotFound);
// Start server
server.begin();
Serial.println("HTTP server started");
}
void loop(void) {
server.handleClient();
}
To do a simple test you can use, as described, a program like Postman, and you must create a POST request
As you can see we specify a raw body in JSON format, and we receive a status 201 (Created to simulate an add of a room on Database) and a JSON response with status “OK”.
On serial output you can see the value passed on post.
Only as exercise I do a check on attribute name and type
if (postObj.containsKey("name") && postObj.containsKey("type")) {
if one of that isn’t present we send a response with 400 as status code (No data found, or incorrect!) and a message detail.
{
"status": "KO",
"message": "No data found, or incorrect!"
}
All other verb
All other verb have the same behaivor of PUT, the only difference is logical, you must use correct verb for the correct operation.
To change the verb you must replace it on the line where the listening server is set
server.on(F("/room"), HTTP_DELETE, room);
and
if (server.method() == HTTP_DELETE) {
Best practices
In a Rest server a best practices is to do an end point (for example /room
) and use verb for the specific operation.
In the example I use /setRoom
to do a set of room, It’s correct technically but incorrect logically.
The correct end point is /room
, and you must use:
- POST: to add new room;
- GET: to get a room;
- DELETE: to delete room;
- and so on.
Thanks
- REST server on esp8266 and esp32: introduction
- REST server on esp8266 and esp32: GET and JSON formatter
- REST server on esp8266 and esp32: POST, PUT, PATCH, DELETE
- REST server on esp8266 and esp32: CORS request, OPTION and GET
- REST server on esp8266 and esp32: CORS request, OPTION and POST