Http module
The Http module is an HTTP client: it makes GET and POST requests to an address and returns what the server answers. Use it to talk to REST APIs, web services or devices on your network. The headers you set apply to every following request, and status() and error() tell how the last one went.
use Http

Platforms
| Windows | ESP32 / ESP32-S3 | ESP32-P4 | ESP32-S31 | |
|---|---|---|---|---|
| The network | The PC's | The WiFi in the board profile | Same | Same |
| HTTPS | Yes, and Windows checks the server's certificate | Yes, but without checking the server's certificate | Yes, and it checks the server's certificate | Same |
| Redirects (301, 302…) | Follows them and returns the final page | Doesn't follow them: returns the redirect's response | Same | Same |
Http.status() when there's no response | 0, or a negative number from -1 to -5 | A negative number, from -1 to -11 (0 if the address can't be understood) | 0, or -1 if the response doesn't arrive | 0, or -1 if the response doesn't arrive |
With Content-Type in setHeader, a post sends | The one from setHeader | The one from post | The one from setHeader | The one from setHeader |
There's no WiFi module: the board connects by itself when it starts, with the network in its profile in ESP32 Tools. It's all in Display, sound, SD and network.
Functions
| Function | What it does | Returns |
|---|---|---|
Http.get(url) | Makes a GET request | The body of the response, or nil if there's no response |
Http.post(url, body) / Http.post(url, body, type) | Makes a POST request | The body of the response, or nil if there's no response |
Http.setHeader(name, value) | Sets a header for the following requests | true |
Http.clearHeaders() | Removes every header | true |
Http.status() | The status code of the last request | An integer |
Http.error() | The error of the last request | A string; empty if there was no error |
Http.timeout() / Http.timeout(ms) | Reads or changes the waiting time | The milliseconds, or true when changing it |
While it waits for the response, the program stops: the screen isn't painted and the callbacks of Timer, MQTT or GPIO don't run.
If you pass them arguments that aren't the ones they expect, none of them throws an exception: they return an error value, which try doesn't catch (see Errors and exceptions).
get(url)
Requests the address url, which starts with http:// or https://, and returns the body of the response as a string.
- If the server answers, it returns what it sends, also if it answers with an error such as 404 or 500. Check
Http.status()to know whether it went well. - If there's no response (no network, the server can't be found, time runs out…), it returns
nil, andHttp.error()says what happened.
use Http
var response = Http.get("https://api.example.com/data")
if (response == nil) then
println("No response: ", Http.error())
elsif (Http.status() == 200) then
println("Response: ", response)
else
println("The server answers ", Http.status())
end
post(url, body, type)
Sends body, a string, to the address url with a POST request. type is optional: the type of the content, sent in the Content-Type header; if you leave it out, "application/json". It returns the same as get.
use Http
var data = '{"temperature": 25.5, "humidity": 60}'
var response = Http.post("https://api.example.com/sensors", data)
if (response != nil) then
println("The server answers ", Http.status(), ": ", response)
else
println("POST error: ", Http.error())
end
With another content type, for instance a form:
use Http
var form = "user=admin&password=secret"
var response = Http.post("https://api.example.com/login", form, "application/x-www-form-urlencoded")
If you've set a Content-Type header with setHeader, on Windows, the P4 and the S31 that one is sent, and on the ESP32 and ESP32-S3, the one from post.
setHeader(name, value)
Sets the header name to value on every following request, until you call clearHeaders(). If there was already one with that name, it changes its value. It returns true.
use Http
Http.setHeader("Authorization", "Bearer my_token")
Http.setHeader("X-API-Key", "secret_key")
// Both headers go in this request and in the following ones
var response = Http.get("https://api.example.com/private")
clearHeaders()
Removes every header you set with setHeader and returns true. Use it when you move from one API to another.
use Http
Http.setHeader("Authorization", "Bearer api_1_token")
Http.get("https://api1.example.com/data")
Http.clearHeaders()
Http.setHeader("X-Custom-Header", "another_value")
Http.get("https://api2.example.com/other-data")
status()
Returns the HTTP status code of the last request: the number the server answers with.
| Code | Meaning |
|---|---|
200 | OK |
201 | Created |
301, 302 | The page has moved (on the boards, which don't follow redirects) |
400 | The request is malformed |
401 | You need to authenticate |
403 | You don't have permission |
404 | It doesn't exist |
500 | Server error |
If there was no response, it's 0 or a negative number, depending on the platform (see Platforms). Before the first request, it's 0.
use Http
var response = Http.get("https://api.example.com/user/123")
var code = Http.status()
switch (code)
case 200:
println("User: ", response)
case 404:
println("That user doesn't exist")
case 401:
println("Not authorized: check the token")
default:
println("Response code: ", code)
end
error()
Returns the error of the last request, or an empty string if there was none. A response with an error code (404, 500…) isn't an error for error(): the server has answered.
| Message | Where | When |
|---|---|---|
Invalid URL | Windows | The address can't be understood. |
Connection error | Windows | It can't connect to the server. |
Network error | Windows | The response doesn't arrive in time, or another network failure. |
Protocol error, Read error, Write error, Generic error | Windows | The conversation with the server fails. |
begin() failed | ESP32 and ESP32-S3 | The address can't be understood. |
GET failed, POST failed | Every board | The request can't be made: no network, the server can't be found, time runs out… On the ESP32 and ESP32-S3, Http.status() gives the reason with its negative number. |
init() failed, write() short | ESP32-P4 and ESP32-S31 | The request can't be prepared, or the whole body can't be sent. |
The name of the chip's error (ESP_ERR_…) | ESP32-P4 and ESP32-S31 | The connection can't be opened. |
use Http
var response = Http.get("https://server-that-does-not-exist.example/api")
if (response == nil) then
println("The request failed: ", Http.error())
end
timeout(ms)
Without arguments, it returns the longest time each request waits, in milliseconds: by default, 10000 (10 seconds). With ms, an integer, it changes it and returns true; a negative value counts as 0.
On Windows, the request is given up once that time and one more second have gone by.
use Http
println("Wait: ", Http.timeout(), " ms") // Wait: 10000 ms
Http.timeout(30000) // 30 seconds, for a slow API
Complete example
A sensor that sends its reading to an API every 30 seconds:
use Http, GPIO
Http.timeout(15000)
Http.setHeader("X-Device-ID", "esp32-sensor-001")
var sensorPin = 34
GPIO.pinmode(sensorPin, GPIO.INPUT)
while (true)
var reading = GPIO.aread(sensorPin)
var temperature = reading * 0.1 // your sensor's conversion
var body = '{"device": "esp32-001", "temp": ' + temperature.toString() + '}'
var response = Http.post("https://api.myserver.com/telemetry", body)
if (response == nil) then
println("No response: ", Http.error())
elsif (Http.status() == 200 or Http.status() == 201) then
println("Sent")
else
println("The server answers ", Http.status())
end
pause(30000)
end
With authentication
First it asks for a token, and then it sends it in the Authorization header. It reads the response with JSON:
use Http, JSON
var login = '{"email": "user@example.com", "password": "pass123"}'
var response = Http.post("https://api.example.com/auth/login", login)
if (response == nil or Http.status() != 200) then
println("I couldn't log in: ", Http.status(), " ", Http.error())
exit(1)
end
var session = JSON.parse(response)
Http.setHeader("Authorization", "Bearer " + session["token"])
var profile = Http.get("https://api.example.com/users/profile")
if (profile != nil and Http.status() == 200) then
var data = JSON.parse(profile)
println("Hello, ", data["name"])
end
With retries
It retries if there's no response or if the server fails (codes 500 and up), but not if the error is in the request:
use Http
func fetch(url)
for (var attempt = 1; attempt <= 3; attempt++)
var response = Http.get(url)
if (response == nil) then
println("No response (", Http.error(), "), attempt ", attempt)
elsif (Http.status() >= 500) then
println("Server error (", Http.status(), "), attempt ", attempt)
elsif (Http.status() >= 400) then
println("Request error: ", Http.status())
return nil
else
return response
end
pause(2000)
end
return nil
end
var data = fetch("https://api.example.com/data")
if (data != nil) then
println("Data: ", data)
end
Pitfalls and known issues
- A 404 doesn't give
nil.getandpostreturn whatever the server answers, whatever the code: always checkHttp.status(). - Argument errors aren't caught. An argument of another type, such as
Http.get(5), doesn't throw an exception: it returns an error value. - The program waits. A request stops the program until the response arrives or time runs out: in a game, the screen freezes for that long.
- Headers stay. What you set with
setHeadergoes in every following request, to other servers too. UseclearHeaders()when you change API. - HTTPS on the ESP32 and ESP32-S3 doesn't check the certificate. The connection is encrypted, but the board doesn't check that the server is who it says it is. Don't send data that must be protected this way.
- Redirects on the boards. If the address redirects to another one (for instance, from
http://tohttps://), on a board you get code301or302: put the final address in the program.
All the known issues of JARU, together, are in Known issues.