Consumindo Web Services JSON-RPC 2.0¶
O ESP32-HTTP-Client oferece suporte nativo e em streaming com zero heap para o protocolo JSON-RPC 2.0 sobre HTTP e HTTPS. Ele serializa automaticamente os envelopes de requisição JSON-RPC 2.0, suporta parâmetros posicionais e nomeados, processa notificações e extrai os resultados diretamente para variáveis C++ e structs mapeadas.
1. Parâmetros Posicionais (Array)¶
No JSON-RPC 2.0, quando os parâmetros são ordenados como um array ("params": [15, 27]), utilize .param(valor) ou .addParam(valor):
#include <Arduino.h>
#include <WiFi.h>
#include "ESP32HTTPClient.h"
ESP32HTTPClient client("https://api.example.com");
void setup() {
Serial.begin(115200);
WiFi.begin("SEU_SSID", "SUA_SENHA");
while (WiFi.status() != WL_CONNECTED) delay(500);
int soma = 0;
// Envia: {"jsonrpc":"2.0","method":"add","params":[15,27],"id":1}
client.jsonRpc("/rpc")
.method("add")
.param(15)
.param(27)
.id(1)
.getResult(&soma);
if (client.isSuccess()) {
Serial.printf("Resultado da soma: %d\n", soma);
}
}
void loop() {}
2. Parâmetros Nomeados (Objeto)¶
Quando o servidor espera parâmetros por nome ("params": {"minuend": 42, "subtrahend": 23}), utilize .param(chave, valor) ou .setParam(chave, valor):
int resultadoSub = 0;
// Envia: {"jsonrpc":"2.0","method":"subtract","params":{"minuend":42,"subtrahend":23},"id":"sub-1"}
client.jsonRpc("/rpc")
.method("subtract")
.param("minuend", 42)
.param("subtrahend", 23)
.id("sub-1")
.getResult(&resultadoSub);
Serial.printf("Resultado da subtração: %d\n", resultadoSub);
3. Notificações (Sem Resposta)¶
De acordo com a especificação JSON-RPC 2.0, uma Notificação é uma requisição sem a propriedade id. O cliente não aguarda nem processa resposta para notificações:
// Envia: {"jsonrpc":"2.0","method":"logTelemetry","params":{"node":"esp32","uptime":120000}}
client.jsonRpc("/rpc")
.method("logTelemetry")
.asNotification()
.param("node", "esp32")
.param("uptime", 120000);
4. Mapeamento de Structs com REST_JSON_MAP¶
Você pode passar structs C++ diretamente nos parâmetros JSON-RPC ou vincular o objeto result diretamente a uma struct sem alocações dinâmicas de documentos JSON:
struct LeituraSensor {
char sensor[32] = {0};
float temperatura = 0.0f;
float umidade = 0.0f;
REST_JSON_MAP(
REST_FIELD(sensor),
REST_FIELD(temperatura),
REST_FIELD(umidade)
)
};
// 1. Enviar struct como objeto de parâmetros:
LeituraSensor dados = {"DHT22", 24.5f, 55.0f};
client.jsonRpc("/rpc")
.method("saveReading")
.setParams(dados)
.id(101);
// 2. Desserializar resultado diretamente para a struct:
LeituraSensor ultimaLeitura;
client.jsonRpc("/rpc")
.method("getLatestReading")
.param("sensorId", 1)
.id(102)
.getResult(&ultimaLeitura);
Serial.printf("Sensor: %s, Temp: %.1f C\n", ultimaLeitura.sensor, ultimaLeitura.temperatura);
5. Tratamento de Erros e Códigos Padrão¶
O JSON-RPC 2.0 retorna erros estruturados no objeto error ({"code": -32601, "message": "Method not found"}). A biblioteca disponibiliza constantes padrão e métodos de inspeção:
JsonRpcError rpcError;
int saida = 0;
client.jsonRpc("/rpc")
.method("metodoInexistente")
.id(5)
.getError(&rpcError)
.onJsonRpcError([](const JsonRpcError& err) {
Serial.printf("Erro JSON-RPC [%d]: %s\n", err.code, err.message.c_str());
})
.getResult(&saida);
if (rpcError.code == JSONRPC_ERR_METHOD_NOT_FOUND) {
Serial.println("O método solicitado não existe no servidor.");
}
Códigos de Erro Padrão JSON-RPC¶
| Constante | Código | Significado |
|---|---|---|
JSONRPC_ERR_PARSE_ERROR |
-32700 |
JSON inválido recebido pelo servidor. |
JSONRPC_ERR_INVALID_REQUEST |
-32600 |
O JSON enviado não é um objeto Request válido. |
JSONRPC_ERR_METHOD_NOT_FOUND |
-32601 |
O método não existe ou não está disponível. |
JSONRPC_ERR_INVALID_PARAMS |
-32602 |
Parâmetros de método inválidos. |
JSONRPC_ERR_INTERNAL_ERROR |
-32603 |
Erro interno do servidor JSON-RPC. |
JSONRPC_ERR_SERVER_ERROR_START até END |
-32099 a -32000 |
Reservados para erros definidos pelo servidor. |
6. Extração de Campos Aninhados e JSON Bruto¶
Utilize a notação de ponto para vincular campos dentro do objeto result, ou capture a string bruta do JSON:
char cidade[64] = {0};
String jsonResultadoBruto;
String corpoHttpCompleto;
client.jsonRpc("/rpc")
.method("getUser")
.param("id", 42)
.id("u42")
.getResult("address.city", cidade, sizeof(cidade)) // Extrai campo aninhado do result
.getRawResult(&jsonResultadoBruto) // Extrai o objeto/array "result" bruto
.getRawResponse(&corpoHttpCompleto); // Extrai o corpo completo da resposta HTTP
7. Exemplo Completo (Sketch)¶
#include <Arduino.h>
#include <WiFi.h>
#include "ESP32HTTPClient.h"
const char* ssid = "SEU_SSID";
const char* password = "SUA_SENHA";
ESP32HTTPClient client("https://api.example.com");
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi Conectado!");
// Opcional: Autenticação Bearer ou cabeçalhos personalizados
client.bearer("seu_token_api");
// 1. Chamada com parâmetros posicionais
int soma = 0;
client.jsonRpc("/rpc")
.method("add")
.param(15)
.param(27)
.id(1)
.getResult(&soma);
Serial.printf("add(15, 27) = %d\n", soma);
// 2. Chamada com parâmetros nomeados e tratamento de erros
int diferenca = 0;
client.jsonRpc("/rpc")
.method("subtract")
.param("minuend", 50)
.param("subtrahend", 12)
.id("sub-1")
.getResult(&diferenca)
.onJsonRpcError([](const JsonRpcError& err) {
Serial.printf("Erro [%d]: %s\n", err.code, err.message.c_str());
});
Serial.printf("subtract(50, 12) = %d\n", diferenca);
// 3. Notificação (sem id, fire-and-forget)
client.jsonRpc("/rpc")
.method("heartbeat")
.asNotification()
.param("node", "esp32");
}
void loop() {}