como-emplear-un-esp8266-como-cliente-de-un-api-rest-con-json

Cómo emplear un ESP8266 o ESP32 como cliente de un API REST con Json

Continuamos con la ESP8266 y el ESP32 y empezamos a meternos en “asuntos serios” de verdad, ya que nos toca ver cómo emplear el ESP8266 como cliente de un API REST que proporcione información a través de ficheros Json.

Haremos referencia al ESP8266, pero el mismo código es compatible para el ESP32, ajustando el nombre de las librerías. Al final tenéis el código tanto para el ESP8266 como para el ESP32.

En las últimas entradas hemos visto múltiples formas de conectar un ESP8266 como servidor con una página web servida al cliente. Así, vimos Ajax y Websockets asíncronos. También vimos en su día cómo emplear el ESP8266 como cliente HTTP.

Como hemos comentado en esta serie de entradas para comunicar dos dispositivos a través de HTTP el servidor tiene que proporcionar un cierto API a través de endpoints. Actualmente lo más habitual es emplear un API REST y el intercambio de información se realice mediante ficheros Json.

Siendo la tendencia a seguir, lo lógico es que en nuestros proyectos con ESP8266 seamos capaces de interactuar y obtener datos de un API REST. Esto es, precisamente, lo que vamos a hacer en esta primera entrada, viendo como actuar como cliente. En la siguiente veremos como servir un API REST desde el ESP8266.

Imaginad, por ejemplo, que tenéis una Raspberry Pi que expone un API donde podemos leer o guardar valores de un sensor. O que actuamos con un servidor en IoT para actuar sobre los distintos servidores.

Para esta entrada usaremos nuestro API REST de ejemplo habitual que vimos en esta entrada, que se ejecuta en NodeJs. También emplearemos de ficheros Json por lo que os recomendamos que leáis la entrada sobre ficheros Json en Arduino.

Con todo eso, tenemos los componentes para hacer nuestro ejemplo de ESP8266 como cliente de un API REST. ¿Cómo de complicado es? Tranquilos, no demasiado si somos organizados. Así que ¡manos a la obra!

En primer lugar, nuestro bucle principal. Es similar al ejemplo de como cliente Http, pero hemos añadido la referencia a ‘ArduinoJson.h’ y a un fichero ‘API.hpp’ que contendrá las funciones a llamar para actuar con el API REST.

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h>

#include "config.h"  // Sustituir con datos de vuestra red
#include "API.hpp"
#include "ESP8266_Utils.hpp"

void setup() 
{
  Serial.begin(115200);
  
   ConnectWiFi_STA();
  
  GetAll();
  GetItem(1);
  GetQuery("ABC");
  Create("New item");
  ReplaceById(2, "New item");
    UpdateById(2, "New item");
  DeleteById(5);
}

void loop() 
{
}

Por otro lado, tenemos el fichero ‘API.hpp’ que contiene las funciones que interactúan con el API REST. Aquí tenemos una función para cada endpoint expuesto por nuestro API REST de ejemplo, y que ilustran las peticiones habituales para Get, Replace, Update y Delete, cada una con sus métodos y con los parámetros necesarios, bien en la URL o en el cuerpo de la petición codificados como Json.

Por otro lado, tenemos la función ‘processResponse(…)’ que se encarga de recoger las respuestas del servidor y realizar con ellas las acciones oportunas. En este caso, simplemente las mostramos por puerto serie. En un proyecto real interpretaríamos los datos recibidos (seguramente otro fichero Json) y ejecutaríamos las acciones oportunas.


String ApiHost = "http://192.168.1.1:8080";

void processResponse(int httpCode, HTTPClient& http)
{
  if (httpCode > 0) {
    Serial.printf("Response code: %d\t", httpCode);

    if (httpCode == HTTP_CODE_OK) {
      String payload = http.getString();
      Serial.println(payload);
    }
  }
  else {
    Serial.printf("Request failed, error: %s\n", http.errorToString(httpCode).c_str());
  }
  http.end();
}

void GetAll()
{
  HTTPClient http;
  http.begin(ApiHost + "/item");
  int httpCode = http.GET();
  processResponse(httpCode, http);
}

void GetItem(int id)
{
  HTTPClient http;
  http.begin(ApiHost + "/item/" + id);
  int httpCode = http.GET();
  processResponse(httpCode, http);
}

void GetQuery(String filter)
{
  HTTPClient http;
  http.begin(ApiHost + "/item?filter=" + filter);
  int httpCode = http.GET();
  processResponse(httpCode, http);
}

void Create(String newData)
{
  HTTPClient http;
  http.begin(ApiHost + "/item");
  http.addHeader("Content-Type", "application/json");
  
  String message = "";
  StaticJsonDocument<300> jsonDoc;
  jsonDoc["data"] = newData;
  serializeJson(jsonDoc, message);
  
  int httpCode = http.POST(message);
  processResponse(httpCode, http);
}

void ReplaceById(int id, String newData)
{
  HTTPClient http;
  http.begin(ApiHost + "/item/" + id);
  http.addHeader("Content-Type", "application/json");

  String message = "";
  StaticJsonDocument<300> jsonDoc;
  jsonDoc["data"] = newData;
  serializeJson(jsonDoc, message);

  int httpCode = http.PUT(message);
  processResponse(httpCode, http);
}

void UpdateById(int id, String newData)
{
  HTTPClient http;
  http.begin(ApiHost + "/item/" + id);
  http.addHeader("Content-Type", "application/json");
  
  String message = "";
  StaticJsonDocument<300> jsonDoc;
  jsonDoc["data"] = newData;
  serializeJson(jsonDoc, message);
  
  int httpCode = http.PATCH(message);
  processResponse(httpCode, http);
}

void DeleteById(int id)
{
  HTTPClient http;
  http.begin(ApiHost + "/item/" + id);
  int httpCode = http.sendRequest("DELETE");
  processResponse(httpCode, http);
}

En este ejemplo, por sencillez, ejecutamos las funciones en el ‘Setup’ para que se lancen una única vez e ilustrar su uso. Por supuesto, en un proyecto las llamaríamos donde las necesitáramos en nuestro código.

Resultado

Si ejecutamos el código veremos que se ejecutan correctamente todas las peticiones al API REST servido en nuestro servidor en NodeJS, y que estamos obteniendo las respuestas enviadas por el servidor.

esp8266-client-api-rest-serial-port

Así como también verificamos que en la consola del servidor en NodeJS estamos recibiendo las peticiones.

esp8266-client-api-rest-nodejs

¿No ha sido demasiado complicado verdad? Ahora ya sabemos cómo interactuar con el ESP8266 como cliente, con un API REST de forma correcta y normalizada.

En la próxima pondremos “la guinda” viendo cómo servir un API REST desde el propio ESP8266. ¡Esto empieza a ponerse en interesante! Hasta pronto.

Descarga el código

Todo el código de esta entrada está disponible para su descarga en Github.

github-full

Versión para el ESP8266: https://github.com/luisllamasbinaburo/ESP8266-Examples

Versión para el ESP32: https://github.com/luisllamasbinaburo/ESP32-Examples