Web Transactions
If your host needs to perform web requests (e.g. GET
, PUT
, POST
, or
DELETE
) with a 3rd-party API or cloud service, the Notecard can facilitate
these requests with the
web.* APIs.
Web transactions are not supported on the Notecard LoRa nor while using NTN mode with Starnote.
- Requirements for Using Web Transactions
- Issuing Web Transactions
- Parsing Web Transaction Responses
- Using Web Transactions Asynchronously
- Sending Large Payloads to Notehub
Requirements for Using Web Transactions
Use of any of the Notecard API's web
requests requires the following:
-
The Notecard must be in
continuous
mode or be temporarily placed incontinuous
mode (with the exception of using web transactions asynchronously).You can place your Notecard into (permanent)
continuous
mode using the hub.set API as shown below:{ "req": "hub.set", "product": "com.your-company.your-name:your_product", "mode": "continuous" }
J *req = NoteNewRequest("hub.set"); JAddStringToObject(req, "product", "com.your-company.your-name:your_product"); JAddStringToObject(req, "mode", "continuous"); NoteRequest(req);
req = {"req": "hub.set"} req["product"] = "com.your-company.your-name:your_product" req["mode"] = "continuous" card.Transaction(req)
Alternatively, if your Notecard is in
periodic
mode, you can use the"on":true
argument to temporarily switch tocontinuous
mode while a web transaction is active. The"seconds"
argument allows you to specify how many seconds the Notecard should remain incontinuous
mode before switching back toperiodic
(the default is300
).{ "req": "hub.set", "on": true, "seconds": 120 }
J *req = NoteNewRequest("hub.set"); JAddBoolToObject(req, "on", true); JAddNumberToObject(req, "seconds", 120); NoteRequest(req);
req = {"req": "hub.set"} req["on"] = True req["seconds"] = 120 card.Transaction(req)
-
The Notecard must have an active connection to Notehub.
When you place a Notecard in
continuous
mode it immediately starts making a connection to Notehub. If you attempt to make anyweb.*
requests before this connection is established, you'll receive the following error:{ "err": "web operations require being online (hub.set)" }
You can check whether your Notecard is actively connected using the hub.status API.
{"req": "hub.status"}
J *req = NoteNewRequest("hub.status"); NoteRequest(req);
req = {"req": "hub.status"} rsp = card.Transaction(req)
When the
hub.status
request returns"connected": true
, you know your Notecard has made a connection with Notehub and you are safe to performweb.*
requests.>{"req":"hub.status"}
{"connected":true}
-
The endpoint to the 3rd-party API or cloud service must be configured as a Route in Notehub using the "Proxy for Notecard Web Requests" type.
This allows the host to avoid hardcoded URLs, keys, and certificates, while relying on Notehub secure authentication mechanisms for performing requests.
Issuing Web Transactions
With these steps complete, you can now use the web.get
, web.put
, web.post
,
and web.delete
requests in accordance with the requirements of the remote
endpoint.
web.get
The Route shown above creates a proxy to a GET
request to a weather endpoint
of the OpenWeatherMap API. The route
argument corresponds to the Alias specified when the proxy Route is created.
{
"req": "web.get",
"route": "GetWeather"
}
J *req = NoteNewRequest("web.get");
JAddStringToObject(req, "route", "GetWeather");
NoteRequest(req);
req = {"req": "web.get"}
req["route"] = "GetWeather"
rsp = card.Transaction(req)
Note that you may optionally enable caching so that web.get
requests
return cached results to reduce latency and provide you with more control over
Consumption Credit
usage (i.e. cached responses do not cost CCs). When handling a web.get
request
with caching enabled, Notehub honors the Cache-Control
response header as per
RFC7234 with a
minimum cache TTL of 5 minutes.
web.put and web.post
For PUT
and POST
requests, a JSON body OR base64-encoded payload can
be provided using the body
or payload
arguments. Unlike the note.add
API,
you cannot use both at the same time in a single web transaction.
{
"req": "web.post",
"route": "SensorService",
"name": "/addReading",
"body": { "temp": 72.32, "humidity": 32.2 }
}
J *req = NoteNewRequest("web.post");
JAddStringToObject(req, "route", "SensorService");
JAddStringToObject(req, "name", "/addReading");
J *body = JCreateObject();
JAddNumberToObject(body, "temp", 72.32);
JAddNumberToObject(body, "humidity", 32.2);
JAddItemToObject(req, "body", body);
NoteRequest(req);
req = {"req": "web.post"}
req["route"] = "SensorService"
req["name"] = "/addReading"
req["body"] = {"temp":72.32, "humidity":32.2}
rsp = card.Transaction(req)
Parsing Web Transaction Responses
For all web requests the Notecard returns the HTTP Status Code in the result
field. If the response also contains a body, that body is provided in the
body
field.
For example, the code below a response from a successful GET
request to the
OpenWeatherMap API.
The Notecard can only accept valid JSON in response to a GET
, POST
, or PUT
request unless you override the default content
argument of application/json
with the appropriate MIME type.
{
"result": 200,
"body": {
"base": "stations",
"clouds": {
"all": 100
},
"cod": 200,
"coord": {
"lat": 42.7,
"lon": -84.5
},
"dt": 1732291278,
"id": 4991640,
"main": {
"feels_like": 274.45,
"grnd_level": 976,
"humidity": 90,
"pressure": 1009,
"sea_level": 1009,
"temp": 278.52,
"temp_max": 279.22,
"temp_min": 277.77
},
"name": "East Lansing",
"rain": {
"1h": 0.25
},
"sys": {
"country": "US",
"id": 2030322,
"sunrise": 1732279144,
"sunset": 1732313392,
"type": 2
},
"timezone": -18000,
"visibility": 10000,
"weather": [
{
"description": "light rain",
"icon": "10d",
"id": 500,
"main": "Rain"
}
],
"wind": {
"deg": 310,
"speed": 6.17
}
}
}
Data returned by a proxy Route is delivered to the Notecard unmodified, by default.
However, you can alter the data before it's sent using a JSONata expression in your route's Inbound Response Transform textarea. As an example refer to the JSONata expression shown in the image above.
This JSONata selects two fields out of the OpenWeatherMap API request—main.temp
and weather.main
—and exclusively includes them in the response. Line 2 of the
JSONata also does some formatting on the temperature, converting it from Kelvin
to Celsius, and rounding its value to two decimal points. (You can learn more about
how JSONata works in
Using JSONata to Transform JSON.)
When this JSONata expression is applied to the earlier OpenWeatherMap API request, it transforms the full JSON response into the following—greatly reducing the amount of data Notehub sends down to your device.
{
"result": 200,
"body": {
"status": "Rain",
"temperature": 5.37
}
}
}
If you're using the Notecard's note-c or note-arduino firmware libraries, you can use the following pattern to parse values out of the returned JSON on your host microcontroller.
J *req = NoteNewRequest("web.get");
if (req != NULL) {
JAddStringToObject(req, "route", "GetWeather");
J *rsp = NoteRequestResponse(req);
J *body = JGetObject(rsp, "body");
if (body != NULL) {
float temp = JGetNumber(body, "temperature");
const char *status = JGetString(body, "status");
}
NoteDeleteResponse(rsp);
}
The Notecard does not store the result of web transactions in Notes. However, Notehub logs all web transactions as events, and you can view them in the Events view of your Notehub project.
If you double click an event and visit its Route log tab, you can view the result of your web transaction in the Notehub UI.
Using Web Transactions Asynchronously
The Notecard also has the ability to perform web transactions asynchronously and retain responses (if any) in a local-only Database Notefile.
For example, if you issued a web.get
request while the Notecard was in
periodic
mode, it will immediately return {"total":1}
(signifying there is
one request pending). When the Notecard next connects to Notehub, it will then
perform any queued web transactions.
By default, the Notecard discards the responses to these transactions, but you
can have the Notecard save the responses in a local-only Database Notefile
(.dbx
) by passing the file
and note
arguments.
{
"req": "web.get",
"route": "GetForecast",
"file": "weather.dbx",
"note": "forecast"
}
J *req = NoteNewRequest("web.get");
JAddStringToObject(req, "route", "GetForecast");
JAddStringToObject(req, "file", "weather.dbx");
JAddStringToObject(req, "note", "forecast");
NoteRequest(req);
req = {"req": "web.get"}
req["route"] = "GetForecast"
req["file"] = "weather.dbx"
req["note"] = "forecast"
rsp = card.Transaction(req)
After the next connection with Notehub, the transaction should be complete and the response available in the specified Notefile.
{
"req": "note.get",
"file": "weather.dbx",
"note": "forecast"
}
J *req = NoteNewRequest("note.get");
JAddStringToObject(req, "file", "weather.dbx");
JAddStringToObject(req, "note", "forecast");
NoteRequest(req);
req = {"req": "note.get"}
req["file"] = "weather.dbx"
req["note"] = "forecast"
rsp = card.Transaction(req)
Sending Large Payloads to Notehub
Consult our guide on Sending and Receiving Large Binary Objects if your application needs to send large binary payloads to Notehub.
Inbound Requests & Shared Data Low Power Design