Serveur API REST ESP32 avec JSON - Tutoriel complet

Exemple WebServerJson - Serveur d'API REST

Vue d'ensemble

Cet exemple montre comment créer un serveur d'API REST sur l'ESP32 qui gère des requêtes et des réponses JSON, parfait pour les applications web modernes et les backends d'applications mobiles.

Fonctionnalités

  • Points de terminaison de l'API REST avec gestion des requêtes et des réponses JSON
  • Traitement des requêtes POST avec analyse des données JSON
  • Points de terminaison GET pour la récupération des données
  • Réponses JSON professionnelles avec des codes d'état HTTP appropriés
  • Gestion des erreurs avec des messages d'erreur JSON appropriés
  • Prise en charge de CORS pour les requêtes entre origines différentes

Préparation du matériel

1×Module de développement ESP32 ESP-WROOM-32
1×Câble USB Type-A vers Type-C (pour PC USB-A)
1×Câble USB Type-C vers Type-C (pour PC USB-C)
1×Recommandé: Carte d'extension à bornier à vis pour ESP32
1×Recommandé: Breakout Expansion Board for ESP32
1×Recommandé: Répartiteur d'alimentation pour ESP32

Ou vous pouvez acheter les kits suivants:

1×Kit de Démarrage DIYables ESP32 (ESP32 inclus)
1×Kit de Capteurs DIYables (30 capteurs/écrans)
1×Kit de Capteurs DIYables (18 capteurs/écrans)
Divulgation : Certains des liens fournis dans cette section sont des liens affiliés Amazon. Nous pouvons recevoir une commission pour tout achat effectué via ces liens, sans coût supplémentaire pour vous. Nous vous remercions de votre soutien.

Installation de la bibliothèque

Suivez ces instructions étape par étape :

  • Si c'est la première fois que vous utilisez l'ESP32, reportez-vous au tutoriel sur Configuration de l'environnement ESP32 dans l'IDE Arduino.
  • Connectez la carte ESP32 à votre ordinateur à l'aide d'un câble USB.
  • Lancez l’IDE Arduino sur votre ordinateur.
  • Sélectionnez la carte ESP32 appropriée (par exemple, ESP32) et le port COM.
  • Ouvrez le Gestionnaire de bibliothèques en cliquant sur l’icône Gestionnaire de bibliothèques sur le côté gauche de l’IDE Arduino.
  • Recherchez Serveur Web pour ESP32 et localisez le mWebSockets par DIYables.
  • Cliquez sur le bouton Install pour ajouter la bibliothèque mWebSockets.
Bibliothèque du serveur Web ESP32

Exemple JSON pour serveur Web

  • Dans l'IDE Arduino, allez dans Fichier Exemples Serveur Web pour ESP32 WebServerJson exemple pour ouvrir le code d'exemple

Points de terminaison API

OBTENIR /api/data

Renvoie un message de succès avec un horodatage au format JSON.

Réponse:

{ "status": "success", "message": "GET request received", "timestamp": 12345 }

La valeur d'horodatage représente des millisecondes écoulées depuis le démarrage de l'ESP32 (à partir de la fonction millis()).

POST /api/data

Accepte des données JSON et renvoie la valeur de la clé reçue.

Demande:

{ "key": "your_value" }

Réponse:

{ "status": "success", "message": "Data received", "received_key": "your_value" }

Instructions d'installation

1. Configuration du réseau

Modifiez les identifiants WiFi dans le fichier WebServerJson.ino :

const char WIFI_SSID[] = "YOUR_WIFI_SSID"; const char WIFI_PASSWORD[] = "YOUR_WIFI_PASSWORD";

2. Téléverser le code et surveiller la sortie

  1. Connectez votre ESP32 à votre ordinateur
  2. Sélectionnez la bonne carte et le port dans l'IDE Arduino
  3. Téléversez le sketch WebServerJson.ino
  4. Ouvrez le Moniteur Série (débit de 9600 bauds)
  5. Attendez la connexion Wi-Fi
  6. Notez l'adresse IP affichée
  7. Si vous ne voyez pas l'adresse IP dans le moniteur série, appuyez sur le bouton de réinitialisation sur la carte ESP32

Utilisation

Tests avec cURL

Remplacez your-esp32-ip par l'adresse IP réelle affichée dans votre moniteur série.

Test de la requête GET
curl -X GET http://your-esp32-ip/api/data

Sortie attendue :

Command Prompt
C:\Users\youruser>curl -X GET http://your-esp32-ip/api/data { "status": "success", "message": "GET request received", "timestamp": 12345 }

L'horodatage indique les millisecondes écoulées depuis le démarrage de l'ESP32.

Test de la requête POST avec des données JSON
curl -X POST http://your-esp32-ip/api/data -H "Content-Type: application/json" -d "{\"key\": \"test_value\"}"

Sortie attendue:

Command Prompt
C:\Users\youruser>curl -X POST http://your-esp32-ip/api/data -H "Content-Type: application/json" -d "{\"key\": \"test_value\"}" { "status": "success", "message": "Data received", "received_key": "test_value" }
Test de la requête POST avec des données différentes
curl -X POST http://your-esp32-ip/api/data -H "Content-Type: application/json" -d "{\"key\": \"hello_world\"}"

Sortie attendue :

Command Prompt
C:\Users\youruser>curl -X POST http://your-esp32-ip/api/data -H "Content-Type: application/json" -d "{\"key\": \"hello_world\"}" { "status": "success", "message": "Data received", "received_key": "hello_world" }
Test JSON invalide (réponse d'erreur)
curl -X POST http://your-esp32-ip/api/data -H "Content-Type: application/json" -d "{invalid json}"

Sortie attendue :

Command Prompt
C:\Users\youruser>curl -X POST http://your-esp32-ip/api/data -H "Content-Type: application/json" -d "{invalid json}" { "status": "error", "message": "Invalid JSON" }
Test d'absence de corps JSON (réponse d'erreur)
curl -X POST http://your-esp32-ip/api/data

Sortie attendue:

Command Prompt
C:\Users\youruser>curl -X POST http://your-esp32-ip/api/data { "status": "error", "message": "No JSON data received" }
Test de méthode non prise en charge (Réponse d'erreur)
curl -X PUT http://your-esp32-ip/api/data -H "Content-Type: application/json" -d "{\"key\": \"test\"}"

Sortie attendue:

Command Prompt
C:\Users\youruser>curl -X PUT http://your-esp32-ip/api/data -H "Content-Type: application/json" -d "{\"key\": \"test\"}" { "status": "error", "message": "Method not allowed" }
Test d'un point de terminaison inexistant (erreur 404)
curl -X GET http://your-esp32-ip/api/nonexistent

Sortie attendue:

Command Prompt
C:\Users\youruser>curl -X GET http://your-esp32-ip/api/nonexistent <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>404 Not Found</title> </head> <body> <h1>404 - Page Not Found</h1> <p>Method: GET</p> <p>Sorry, we couldn't find that page!</p> <a href="/">Return to Home</a> </body> </html>

Tests avec Postman

Test de requête GET
  1. Créer une nouvelle requête GET
  2. Définir l'URL sur http://your-esp32-ip/api/data
  3. Envoyer la requête
  4. Vérifier que la réponse contient le statut, le message et l'horodatage
Requête POST de test
  1. Créer une nouvelle requête POST
  2. Définir l'URL sur http://your-esp32-ip/api/data
  3. Ajouter l'en-tête : Content-Type: application/json
  4. Ajouter le corps JSON : {"key": "test_value"}
  5. Envoyer la requête
  6. Vérifier que la réponse affiche la valeur de la clé reçue

Tests des réponses d'erreur

Testez la gestion des erreurs en envoyant des requêtes invalides comme indiqué dans le code d'exemple :

Données JSON manquantes
curl -X POST http://your-esp32-ip/api/data

{"status": "error","message": "Aucune donnée JSON reçue"}

Format JSON invalide
curl -X POST http://your-esp32-ip/api/data -H "Content-Type: application/json" -d "{invalid json}"

Attendu: {"status": "erreur","message": "JSON invalide"}

Champ clé manquant
curl -X POST http://your-esp32-ip/api/data -H "Content-Type: application/json" -d "{\"other_field\": \"value\"}"

Attendu : La clé prendra la valeur par défaut "none" selon le code d'exemple : doc["key"] | "none"

Méthode HTTP non prise en charge
curl -X DELETE http://your-esp32-ip/api/data

Attendu: {"status": "erreur","message": "Méthode non autorisée"}

Explication du code

Configuration des itinéraires

// Configure API routes server.addRoute("/api/data", handleApiData);

Signature de la fonction gestionnaire

Toutes les fonctions de gestionnaire doivent suivre cette signature :

void handleApiData(WiFiClient& client, const String& method, const String& request, const QueryParams& params, const String& jsonData) { // Handler implementation }

Détection de méthode et traitement JSON

void handleApiData(WiFiClient& client, const String& method, const String& request, const QueryParams& params, const String& jsonData) { Serial.print("[API] "); Serial.print(method); Serial.print(" request received"); if (method == "POST") { if (jsonData.length() == 0) { Serial.println("Error: No JSON data received"); client.println("HTTP/1.1 400 Bad Request"); client.println("Content-Type: application/json"); client.println("Connection: close"); client.println(); client.print("{\"status\": \"error\",\"message\": \"No JSON data received\"}"); return; } StaticJsonDocument<200> doc; DeserializationError error = deserializeJson(doc, jsonData); if (!error) { const char* key = doc["key"] | "none"; String response = JSON_RESPONSE; response.replace("%KEY%", key); server.sendResponse(client, response.c_str(), "application/json"); } else { client.println("HTTP/1.1 400 Bad Request"); client.println("Content-Type: application/json"); client.println("Connection: close"); client.println(); client.print("{\"status\": \"error\",\"message\": \"Invalid JSON\"}"); } } else if (method == "GET") { String response = JSON_GET_RESPONSE; response.replace("%TIMESTAMP%", String(millis())); server.sendResponse(client, response.c_str(), "application/json"); } else { client.println("HTTP/1.1 405 Method Not Allowed"); client.println("Content-Type: application/json"); client.println("Connection: close"); client.println(); client.print("{\"status\":\"error\",\"message\":\"Method not allowed\"}"); } }

Exemples d'intégration

JavaScript côté client

// Control LED async function controlLED(action) { try { const response = await fetch('http://your-esp32-ip/api/led', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ action: action }) }); const result = await response.json(); console.log('LED control result:', result); } catch (error) { console.error('Error:', error); } } // Get sensor data async function getSensorData() { try { const response = await fetch('http://your-esp32-ip/api/sensor'); const data = await response.json(); console.log('Sensor data:', data); } catch (error) { console.error('Error:', error); } }

Client Python

import requests import json

Contrôle LED

def control_led(action): url = "http://your-esp32-ip/api/led" data = {"action": action} response = requests.post(url, json=data) return response.json()

Obtenir le statut

def get_status(): url = "http://your-esp32-ip/api/status" response = requests.get(url) return response.json()

Utilisation

result = control_led("on") print(result) status = get_status() print(status)

Gestion des erreurs

Codes d'état HTTP

  • 200: Succès
  • 400: Mauvaise requête (JSON invalide, paramètres manquants)
  • 404: Point d'accès introuvable
  • 405: Méthode non autorisée
  • 500: Erreur interne du serveur

Format de réponse d'erreur

Selon le code d'exemple réel, différentes erreurs renvoient des messages spécifiques :

Erreur de données JSON manquantes
{ "status": "error", "message": "No JSON data received" }

Renvoyé lorsque : La requête POST est envoyée sans corps JSON

Erreur de format JSON invalide
{ "status": "error", "message": "Invalid JSON" }

Renvoyé lorsque : les données JSON ne peuvent pas être analysées (erreurs de syntaxe)

Erreur : Méthode non autorisée
{ "status": "error", "message": "Method not allowed" }

Renvoyé lorsque : Utilisation de méthodes HTTP non prises en charge (PUT, DELETE, PATCH, etc.)

Erreur 404 Introuvable
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>404 Not Found</title> </head> <body> <h1>404 - Page Not Found</h1> <p>Method: [HTTP_METHOD]</p> <p>Sorry, we couldn't find that page!</p> <a href="/">Return to Home</a> </body> </html>

Renvoyé lorsque : l’accès à des points de terminaison inexistants

Personnalisation

Ajout de nouvelles fonctions de gestion

// Create additional handler for a new endpoint void handleApiStatus(WiFiClient& client, const String& method, const String& request, const QueryParams& params, const String& jsonData) { if (method == "GET") { String json = "{\"status\":\"online\",\"uptime\":" + String(millis() / 1000) + "}"; server.sendResponse(client, json.c_str(), "application/json"); } else { client.println("HTTP/1.1 405 Method Not Allowed"); client.println("Content-Type: application/json"); client.println("Connection: close"); client.println(); client.print("{\"status\":\"error\",\"message\":\"Method not allowed\"}"); } } // Register the new route in setup() server.addRoute("/api/status", handleApiStatus);

Réponses JSON basées sur des modèles

L'exemple utilise des chaînes de gabarit pour un formatage JSON cohérent :

const char JSON_RESPONSE[] PROGMEM = R"rawliteral( { "status": "success", "message": "Data received", "received_key": "%KEY%" } )rawliteral"; // Usage in handler String response = JSON_RESPONSE; response.replace("%KEY%", extractedValue); server.sendResponse(client, response.c_str(), "application/json");

Dépannage

Problèmes courants

Problèmes de connexion

Si vous ne pouvez pas vous connecter aux points de terminaison de l’API :

  1. Vérifiez que votre ESP32 est connecté au Wi-Fi (vérifiez le moniteur série)
  2. Assurez-vous que votre client et l'ESP32 sont sur le même réseau
  3. Vérifiez que l'adresse IP est correcte
  4. Vérifiez que l'ESP32 ne s'est pas réinitialisé (ce qui changerait l'adresse IP)

Erreurs d'analyse JSON

Si vous obtenez des réponses JSON invalides:

  1. Assurez-vous que l'en-tête Content-Type est défini sur application/json
  2. Vérifiez que votre syntaxe JSON est valide
  3. Vérifiez que les caractères spéciaux sont correctement échappés
  4. Assurez-vous que la charge utile JSON n'est pas trop grande (limite actuelle : 200 octets)

Problèmes de requêtes POST

Si les requêtes POST renvoient « Aucune donnée JSON reçue » :

  1. Vérifiez que vous envoyez un corps JSON avec la requête
  2. Vérifiez que l'en-tête Content-Length est correctement défini
  3. Assurez-vous que la méthode HTTP est bien POST
  4. Testez avec un JSON simple tel que {"key": "test"}

Problèmes de mémoire

Si l'ESP32 ne répond plus :

  1. Surveiller l'utilisation de la mémoire - le StaticJsonDocument utilise 200 octets
  2. Réduire la taille du modèle JSON_RESPONSE si nécessaire
  3. Envisagez d'utiliser DynamicJsonDocument pour des données de taille variable
  4. Vérifier les fuites de mémoire dans les fonctions de gestion personnalisées

Conseils de performance

Optimiser le traitement JSON

// Use appropriate document size for your data StaticJsonDocument<200> doc; // For small JSON objects StaticJsonDocument<1024> doc; // For larger JSON objects // Reuse string objects to reduce memory allocation String response; response.reserve(256); // Pre-allocate space response = JSON_RESPONSE; response.replace("%KEY%", value);

Gestion efficace des réponses

// Send responses directly for simple cases client.print(F("{\"status\":\"ok\",\"value\":")); client.print(sensorValue); client.print(F("}")); // Use PROGMEM for large static responses const char LARGE_RESPONSE[] PROGMEM = R"({ "status": "success", "data": { ... } })";

Prochaines étapes

  • Explorez WebServerQueryStrings.ino pour la gestion des paramètres d'URL
  • Essayez WebServerWithWebSocket.ino pour la communication en temps réel
  • Envisagez l'intégration avec des bases de données ou des services cloud

Ressources d'apprentissage

※ NOS MESSAGES

  • N'hésitez pas à partager le lien de ce tutoriel. Cependant, veuillez ne pas utiliser notre contenu sur d'autres sites web. Nous avons investi beaucoup d'efforts et de temps pour créer ce contenu, veuillez respecter notre travail !