How To Send Unsecured and Secured API Requests with Arduino
2024-12-11 | By Maker.io Staff
IoT projects typically necessitate communication between embedded devices and an external server, such as a remote storage device that collects data from multiple clients. The most common way of exchanging data is using well-established communication protocols, such as HTTP and HTTPS. This article explains how you can send and receive data with an Arduino using the platform’s standard libraries.
Updating the WiFi NiNa Firmware
Outdated versions of the NiNa driver may prevent the Arduino from verifying server certificates, leading to connection issues with encrypted API endpoints. Therefore, you should ensure your Arduino runs the latest WiFi firmware before proceeding.
To update the firmware of a supported Arduino board (Uno, Nano, MKR, and Portenta), connect it to the computer, open the Arduino IDE, and close the serial monitor if it is open. Then, launch the firmware updater tool from the app’s main menu bar:
Use the Arduino IDE’s main menu bar to open the Firmware Updater tool.
Select the board from the dropdown menu and click the “check updates” button. Then, choose the firmware version to install from the second dropdown menu that appears. Most likely, you should select the most recent version unless you have a reason for installing a specific version. Note that updating the firmware erases the sketch on the board:
Follow the highlighted steps to update the WiFi NINA module firmware on the Arduino Nano RP2040 Connect to resolve certificate-related connectivity issues.
The tool downloads and installs the latest firmware, displaying a success message once it finishes. If the installation fails, you can always retry the process. Finally, disconnect and reconnect the board to the computer before uploading a sketch.
Establishing a WiFi Connection
The Arduino board needs to establish a wireless connection to an existing network before it can fetch data or send information to an external API. The setup function is the perfect place for this code, as it only needs to run once at startup:
#include <WiFiNINA.h> // Arduino Nano RP2040 Connect const char* SSID = "your_SSID"; const char* PASSWORD = "your_PASSWORD"; void setup() { Serial.begin(9600); int status = WL_IDLE_STATUS; do { status = WiFi.begin(SSID, PASSWORD); delay(2000); } while (WiFi.status() != WL_CONNECTED); } void loop() { /* Code for communicating with an API */ }
Different boards require different import statements to allow the sketch to communicate with the device’s wireless network controller. This example uses the Arduino Nano RP2040 Connect, which utilizes the WiFi NINA module.
The two constants beneath the import statement are pointers to the network’s SSID and password. The setup code tries to establish a connection to the specified network, and it sits in the do-while loop until the process succeeds, waiting two seconds between attempts.
Requesting Data from Unencrypted API Endpoints
Before sending requests, developers must install the ArduinoHttpClient and WiFiNINA libraries using the Arduino IDE’s library manager.
After that, fetching data from an unencrypted API is as easy as dispatching a single request, usually an HTTP GET request. Programmers can often supply additional parameters when making remote API calls to request specific information from the API or authenticate themselves. In GET requests, these parameters are usually provided in one of two ways, either as part of the URL or with the HTTP request header. The following snippet demonstrates both approaches.
/* Previous import statements omitted */ #include <ArduinoHttpClient.h> /* Previous constants omitted */ const char* API_ADDRESS = "192.168.0.103"; const char* API_URL = "/api/v2/temperatures"; const char* API_KEY = "your_API_KEY"; const unsigned int API_PORT = 80; WiFiClient wifi; HttpClient http = HttpClient(wifi, API_ADDRESS, API_PORT); void setup() { /* Setup code omitted */ } void loop() { String url = String(API_URL) + "?param=value&other_param=value"; http.beginRequest(); http.get(url); http.sendHeader("auth", String(API_KEY)); http.endRequest(); int statusCode = http.responseStatusCode(); if (statusCode >= 200 && statusCode < 300) { String payload = http.responseBody(); Serial.println(payload); } else { Serial.print("Error in HTTP request: "); Serial.println(statusCode); } /* Perform other tasks between requests */ }
This snippet adds another import statement necessary for dispatching HTTP requests. The constants define the server’s IP address, the resource URL, and the port. You can also supply the server’s URL (without a protocol) instead of the IP address. Lastly, the snippet also contains a dummy API key to be passed on with the request header.
The loop function populates the URL parameter values. In this example, the Arduino passes two additional parameters to the API. The code then initializes the HttpClient with the URL and adds the API key to the request header. The get() function call instructs the library to send this request as a GET HTTP request. The endRequest function dispatches the call to the API and records the server’s response.
A response code between 200 and 299 indicates success, and the program prints the response to the serial console if the code is between 200 and 299. Otherwise, the loop method outputs the error code.
Sending Data to Unencrypted API Endpoints
The code for sending data to an unsecured API endpoint is similar to the previous snippet. However, instead of using the get() call to send an HTTP GET request, developers must typically use a POST, PUT, PATCH, or DELETE call, depending on the API and the action to perform.
Usually, POST is used to create new data, PUT and PATCH are used to update values stored on the server and DELETE is used to remove entries from the server. For these requests, developers typically send data as part of the request body:
/* Build the URL, etc., like above */ String payload = "{\"param\":\"value\"}"; http.beginRequest(); http.post(url); http.sendHeader("auth", String(API_KEY)); http.sendHeader("Content-Type", "application/json"); http.beginBody(); http.print(payload); http.endRequest(); /* Check HTTP Code for errors */
The only difference between the methods is how data is sent to the API. In this example, the JSON payload contains a single parameter, which must be passed to the library after calling the beginBody() method. Like before, endRequest() dispatches the API call.
Sending HTTPs Requests to Encrypted Endpoints
Making encrypted calls to external APIs over HTTPS only requires minimal changes to the code discussed so far. Namely, you must import an additional library and exchange the WiFiClient used above for the secured WiFiSSLClient. Further, updating the port to 443 is often required, as port 80 is typically only used for unsecured HTTP requests:
/* Other imports from before */ #include <WiFiSSLClient.h> /* Other constants omitted */ const unsigned int API_PORT = 443; WiFiSSLClient wifi; HttpClient http = HttpClient(wifi, API_ADDRESS, API_PORT); void setup() { /* Same as above */ } void loop() { /* Same as above */ }
The most recent version of the official Arduino WiFiSSLClient automatically verifies the server’s root certificate, removing the need for manually added certificates in the source code and making working with secured APIs more straightforward than ever.
Summary
Most IoT projects require transmitting data from an embedded device to a remote server and vice versa. The official Arduino HttpClient library makes managing HTTP and HTTPS calls easy.
The data exchange process between an Arduino and a server starts with establishing a network connection. Next, the program needs to open a server connection and specify the request type (GET, POST, PUT, etc.). Depending on the request and the API, developers may need to add supplementary URL parameters, headers, or a payload in the request body. Once dispatched, developers can check the HTTP code to inspect the server’s response and obtain the response body.
Working with secured endpoints is straightforward, and developers only need to change a single line of code to ensure their program uses the WiFiSSLClient class instead of the unsecured WiFiClient variant. However, it’s essential that you update the Arduino’s firmware to the most recent version to prevent certificate-related issues, which can be incredibly frustrating to troubleshoot.
Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.
Visit TechForum