Language: EN

como-servir-y-consumir-un-api-rest-con-esp8266-y-axios

How to Serve and Consume a REST API with ESP8266 or ESP32 and Axios

Continuing with the section of posts dedicated to the ESP8266 and the ESP32. This time we will see how to integrate the popular AXIOS library to make AJAX requests from a web client to a REST API served from the ESP8266.

We will refer to the ESP8266, but the same code is compatible with the ESP32, adjusting the name of the libraries. At the end you have the code for both the ESP8266 and the ESP32.

It has been several posts since we saw how to serve a REST API from the ESP8266. On the other hand, in the last two posts we made a small “break” to see the VueJS and Vuetify frameworks.

Of course, the goal of the next posts is to integrate all these components to serve an application in VueJS/Vuetify that communicates with a REST API served from the ESP8266. So in this post we will see how to make this communication through the REST API.

To do this we are going to see another component, the AXIOS library, a popular library in Javascript for making requests. AXIOS will allow us to make AJAX requests in the client in a cleaner way.

To see its use we are going to base ourselves on the post in which we served our example REST API, correctly formatted, and we are going to adapt it to illustrate the communication with the client using AXIOS. Logically, the change in relation to this post mainly affects the client, so the entire backend part will not have any changes.

That is, the main program of the ESP8266 remains the same.

#include <ESP8266WiFi.h>
#include <ESPAsyncWebServer.h>
#include <FS.h>
#include <ArduinoJson.h>

#include "config.h"  // Replace with your network data
#include "API.hpp"
#include "Server.hpp"
#include "ESP8266_Utils.hpp"

void setup(void)
{
  Serial.begin(115200);
  SPIFFS.begin();
  
  ConnectWiFi_STA();
  
  InitServer();
}

void loop(void)
{
}

As well as the server definition in the ‘Server.hpp’ file.

AsyncWebServer server(80);

void notFound(AsyncWebServerRequest *request) {
  request->send(404, "text/plain", "Not found");
}

void InitServer()
{
  server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.html");
  
  server.on("/item", HTTP_GET, getRequest);
  server.on("/item", HTTP_POST, [](AsyncWebServerRequest * request){}, NULL, postRequest);
  server.on("/item", HTTP_PUT, [](AsyncWebServerRequest * request){}, NULL, putRequest);
  server.on("/item", HTTP_PATCH, [](AsyncWebServerRequest * request){}, NULL, patchRequest);
  server.on("/item", HTTP_DELETE, deleteRequest);
  
  server.onNotFound(notFound);

  server.begin();
    Serial.println("HTTP server started");
}

And the served REST API that we have defined in the ‘API.hpp’ file.

#include "ESP8266_Utils_APIREST.hpp"

const char* PARAM_FILTER = "filter";

void getAll(AsyncWebServerRequest *request)
{
  String message = "Get All";
  Serial.println(message);
  request->send(200, "text/plain", message);
}

void getFiltered(AsyncWebServerRequest *request)
{
  String message = "Get filtered by " + request->getParam(PARAM_FILTER)->value();
  Serial.println(message);
  request->send(200, "text/plain", message);
}

void getById(AsyncWebServerRequest *request)
{
  int id = GetIdFromURL(request, "/item/");

  String message = String("Get by Id ") + id;
  Serial.println(message);
  request->send(200, "text/plain", message);
}

void getRequest(AsyncWebServerRequest *request) {
  
  if (request->hasParam(PARAM_FILTER)) {
    getFiltered(request);
  }
  else if(request->url().indexOf("/item/") != -1)
  {
    getById(request);
  }
  else {
    getAll(request);
  }
}

void postRequest(AsyncWebServerRequest * request, uint8_t *data, size_t len, size_t index, size_t total)
{ 
  String bodyContent = GetBodyContent(data, len);
  
  StaticJsonDocument<200> doc;
  DeserializationError error = deserializeJson(doc, bodyContent);
  if (error) { request->send(400); return;}

  String string_data = doc["data"];
  String message = "Create " + string_data;
  Serial.println(message);
  request->send(200, "text/plain", message);
}

void patchRequest(AsyncWebServerRequest * request, uint8_t *data, size_t len, size_t index, size_t total)
{
  int id = GetIdFromURL(request, "/item/");
  String bodyContent = GetBodyContent(data, len);
  
  StaticJsonDocument<200> doc;
  DeserializationError error = deserializeJson(doc, bodyContent);
  if (error) { request->send(400); return;}

  String string_data = doc["data"];
  String message = String("Update ") + id + " with " + string_data;
  Serial.println(message);
  request->send(200, "text/plain", message);
}

void putRequest(AsyncWebServerRequest * request, uint8_t *data, size_t len, size_t index, size_t total)
{
  int id = GetIdFromURL(request, "/item/");
  String bodyContent = GetBodyContent(data, len);
   
  StaticJsonDocument<200> doc;
  DeserializationError error = deserializeJson(doc, bodyContent);
  if (error) { request->send(400); return;}

  String string_data = doc["data"];
  String message = String("Replace ") + id + " with " + string_data;
  Serial.println(message);
  request->send(200, "text/plain", message);
}

void deleteRequest(AsyncWebServerRequest *request) {
  int id = GetIdFromURL(request, "/item/");

  String message = String("Delete ") + id;
  Serial.println(message);
  request->send(200, "text/plain", message);
}

Now let’s go to the client, where we will have significant changes.

The ‘index.html’ file changes to include the AXIOS library either from CDN (commented) or from the memory of the ESP8266.

<!DOCTYPE html>
<html>
  <head>
    <title>ESP8266 Axios</title>
    <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <div>
            <div>
                <button onclick="getAllRequest()">Get All</button>
                <button onclick="getFilteredRequest()">Get Filtered</button>
                <button onclick="getByIdRequest()">Get by Id</button>
            </div>
            <div>
                <button onclick="postRequest()">Create</button>
            </div>
            <div>
                <button onclick="patchRequest()">Update</button>
            </div>
            <div>
                <button onclick="putRequest()">Replace</button>
            </div>
            <div>
                <button onclick="deleteRequest()">Delete</button>
            </div>
        </div>
        
        <!-- From CDN -->
        <!--<script src="https://cdn.jsdelivr.net/npm/axios@0.18.0/dist/axios.min.js"></script>-->
        <script type="text/javascript" src="./vendor/axios.min.js"></script>

        <script src="./js/API.js"></script>
    </body>
</html>

On the other hand, we have externalized all the functions to call our REST API in the ‘API.js’ file, which contains the example functions for the respective calls made using the AXIOS library.

function getAllRequest()
{
  axios.get('item')
    .then(function (response) {
    console.log(response);
    })
    .catch(function (error) {
    console.log(error);
    })
    .then(function () {
    });
}

function getFilteredRequest()
{
  axios.get('item', {
    params: {
      filter : 'myFilter'
    }
    })
    .then(function (response) {
    console.log(response);
    })
    .catch(function (error) {
    console.log(error);
    })
    .then(function () {
    });
}

function getByIdRequest()
{
  id = 10;
  axios.get('item/' + id)
    .then(function (response) {
    console.log(response);
    })
    .catch(function (error) {
    console.log(error);
    })
    .then(function () {
    });
}

function postRequest()
{
  axios.post('item', {
    data: 'NewItem'
    })
    .then(function (response) {
    console.log(response);
    })
    .catch(function (error) {
    console.log(error);
    })
    .then(function () {
    });
}

function putRequest()
{
  id = 10;
  axios.put('item/' + id, {
    data: 'NewItem'
    })
    .then(function (response) {
    console.log(response);
    })
    .catch(function (error) {
    console.log(error);
    })
    .then(function () {
    });
}

function patchRequest()
{
  id = 10;
  axios.patch('item/' + id, {
    data: 'NewItem'
    })
    .then(function (response) {
    console.log(response);
    })
    .catch(function (error) {
    console.log(error);
    })
    .then(function () {
    });
}

function deleteRequest()
{
  id = 10;
  axios.delete('item/' + id)
    .then(function (response) {
    console.log(response);
    })
    .catch(function (error) {
    console.log(error);
    })
    .then(function () {
    });
}

Result

If we load everything on the ESP8266, and access the served web page, we will see our simple (and yes, ugly again) interface to test that we connect correctly with the REST API.

esp8266-apirest-client

If we click on the different buttons, we can check how, indeed, the backend in the ES8266 correctly receives the requests and shows the appropriate data in the command console.

esp8266-client-api-rest-nodejs

As we can see, it is very easy to integrate AXIOS in the ESP8266. This small library will simplify our work in our projects, especially when working with REST APIs, making our code simpler and more maintainable.

Of course, it is only an example to illustrate the communication. In a real project, it would be necessary to define the REST API, complete the entire web interface, and perform the actions we want in the backend. But the example contains all the necessary code to make CRUD requests (get/post/update/delete) both in the backend and in the frontend.

In the next two posts, we will continue to improve this example, especially the web interface part, adding the integration of the REST API and AXIOS to our solutions along with VueJS and Vuetify. See you soon!

Download the code

All the code from this post is available for download on Github.

github-full

Version for the ESP8266: https://github.com/luisllamasbinaburo/ESP8266-Examples

Version for the ESP32: https://github.com/luisllamasbinaburo/ESP32-Examples