Transforming JSON responses
The REST API allows you to retrieve information about a device using the
FetchDevice endpoint.
The JSON responses for devices can be large, especially for Bluetooth® Low
Energy (LE) devices. Here is a JSON example for a Thingy:52:
{
"id": "CA:B2:31:EE:E0:9E",
"name": "CA:B2:31:EE:E0:9E",
"type": "BLE",
"tags": [],
"state": {
"1800": {
"uuid": "1800",
"characteristics": {
"2A00": {
"uuid": "2A00",
"path": "1800/2A00",
"value": [
65,
112,
112,
108,
101,
32,
84,
86
],
"properties": {
"broadcast": false,
"read": true,
"writeWithoutResponse": false,
"write": false,
"notify": false,
"indicate": false,
"authorizedSignedWrite": false
},
"descriptors": {}
},
"2A01": {
"uuid": "2A01",
"path": "1800/2A01",
"value": [
128,
2
],
"properties": {
"broadcast": false,
"read": true,
"writeWithoutResponse": false,
"write": false,
"notify": false,
"indicate": false,
"authorizedSignedWrite": false
},
"descriptors": {}
}
}
},
"1801": {
"uuid": "1801",
"characteristics": {
"2A05": {
"uuid": "2A05",
"path": "1801/2A05",
"value": [],
"properties": {
"broadcast": false,
"read": false,
"writeWithoutResponse": false,
"write": false,
"notify": false,
"indicate": true,
"authorizedSignedWrite": false
},
"descriptors": {
"2902": {
"uuid": "2902",
"value": [
0,
0
],
"path": "1801/2A05/2902"
}
}
}
}
},
"D0611E78BBB44591A5F8487910AE4366": {
"uuid": "D0611E78BBB44591A5F8487910AE4366",
"characteristics": {
"8667556C9A374C9184ED54EE27D90049": {
"uuid": "8667556C9A374C9184ED54EE27D90049",
"path": "D0611E78BBB44591A5F8487910AE4366/8667556C9A374C9184ED54EE27D90049",
"value": [],
"properties": {
"broadcast": false,
"read": false,
"writeWithoutResponse": false,
"write": true,
"notify": true,
"indicate": false,
"authorizedSignedWrite": false
},
"descriptors": {
"2900": {
"uuid": "2900",
"value": [
1,
0
],
"path": "D0611E78BBB44591A5F8487910AE4366/8667556C9A374C9184ED54EE27D90049/2900"
},
"2902": {
"uuid": "2902",
"value": [
0,
0
],
"path": "D0611E78BBB44591A5F8487910AE4366/8667556C9A374C9184ED54EE27D90049/2902"
}
}
}
}
}
},
"$meta": {
"version": "1.0",
"createdAt": "2018-11-06T22:20:15.417Z",
"updatedAt": "2018-11-06T22:20:44.676Z"
}
}
In some cases, you might want to fetch only a subset of the information the server gives you. You can control which information is returned using a transform.
Concepts
A transform is a JSONata expression that you send as a query string parameter, which transforms one or more resources in the default JSON response. JSONata is a REST-based analog to GraphQL, because you can express what the response should contain and how it is shaped.
The API provides transform support only for the
FetchDevice and
ListDevices endpoints.
Basic examples
This section contains basic transform examples.
Example: fetching all device IDs
If you want to fetch the IDs of all your devices, transform the response with
transform=id:
export API_KEY=YOUR_API_KEY
curl --request GET \
--url "https://api.nrfcloud.com/v1/devices?includeState=true&transform=id" \
--header "Authorization: Bearer $API_KEY"
Instead of all device data, you receive an abbreviated list:
{
"items": [
"CA:B2:31:EE:E0:9E",
"ba4130fc-5d1f-423b-bd1c-05213932a884",
"MyGenericDevice1"
],
"total": 3
}
Example: Bluetooth LE device IDs
Use transform=type='BLE' ? id to return only the IDs of Bluetooth LE devices:
curl --request GET \
--url "https://api.nrfcloud.com/v1/devices?includeState=true&transform=type='BLE' ? id" \
--header "Authorization: Bearer $API_KEY"
The server returns the IDs for Bluetooth LE devices added to your team, and
null for devices that do not match the transform:
{
"items": [
"CA:B2:31:EE:E0:9E",
null,
null
],
"total": 3
}
Example: filtering by device type
If you are filtering by device type, use the deviceTypes parameter and pass in
BLE:
curl --request GET \
--url "https://api.nrfcloud.com/v1/devices?transform=id&deviceTypes=BLE" \
--header "Authorization: Bearer $API_KEY"
Example: returning ID and device type
The following command returns a JSON object containing the id and type of
all your devices:
curl --request GET \
--url "https://api.nrfcloud.com/v1/devices?includeState=true&transform=\{ 'id': id, 'type': type \}" \
--header "Authorization: Bearer $API_KEY"
The server returns a list of devices by ID and type:
{
"items": [
{
"id": "CA:B2:31:EE:E0:9E",
"type": "BLE"
},
{
"id": "ba4130fc-5d1f-423b-bd1c-05213932a884",
"type": "Gateway"
},
{
"id": "MyGenericDevice1",
"type": "Generic"
}
],
"total": 3
}
Considerations
There are a few things to consider for these examples:
- Although strict JSONata syntax requires valid JSON, which requires double quotes around field names, the REST API accepts single or double quotes. Whichever you choose, wrap the entire URL in the opposite type of quotes from the field names, as in these examples.
- In the
transform, values that are not wrapped in quotes are considered variables that map to the transformed resource. In this case, the JSON for the resource contains both anidandtypeproperty, which return as values for fields of the same name. You can give the field any name you want, such asdeviceIdanddeviceType. - If you use shell environment variables such as API_KEY as in these examples, they must be either unquoted or in double quotes so the shell substitutes the value for the variable name.
- You must escape braces with a backslash (
\{and\}), or cURL interprets them as two different HTTP requests and sends them in a syntax that the REST API does not accept. If you are using another REST API utility like Insomnia or Postman, you do not need to escape braces.
Advanced transforms
The previous examples worked with top-level properties of the Device resource.
You can also use a transform to retrieve and shape data deep within the
resource's JSON representation.
Example: characteristics
You can retrieve only the characteristics and their values from the Bluetooth LE example at the top of this page with the following command:
curl --request GET \
--url "https://api.nrfcloud.com/v1/devices/CA:B2:31:EE:E0:9E?transform=\{ 'id': id, 'characteristics': $map(state.*.characteristics.*, function($c) \{ \{'uuid': $c.uuid, 'value': $c.value \} \})\}" \
--header "Authorization: Bearer $API_KEY"
This returns the following response:
{
"id": "CA:B2:31:EE:E0:9E",
"characteristics": [
{
"uuid": "2A00",
"value": [
65,
112,
112,
108,
101,
32,
84,
86
]
},
{
"uuid": "2A01",
"value": [
128,
2
]
},
{
"uuid": "2A05",
"value": []
},
{
"uuid": "8667556C9A374C9184ED54EE27D90049",
"value": []
}
]
}
The JSONata Exerciser UI lets you simplify JSONata syntax for transforms. The exerciser requires double quotes around all field names.
Example: GET /devices and device types
If you want to call the GET /devices endpoint to fetch all of your devices,
but apply a different transform per device type, use a ternary expression:
type = 'BLE' ? { 'id': id, 'characteristics': $map(state.*.characteristics.*, function($c) { {'uuid': $c.uuid, 'value': $c.value } })} : { 'id': id, 'reportedName': state.reported.name, 'connectedBLEDevices': $keys(state.reported.statusConnections) }
This applies one transform to Bluetooth LE types, and another to all the other
(IP-based) types. However, this can get more complicated if you want to
conditionally apply a third transform, because JSONata does not support
switch/case.
Transforms only work on the JSON of a Device resource, not on the entire
JSON response, which might contain metadata, paging data, and more. When
experimenting with JSONata, paste in the JSON for a single resource to work out
the transformation expression. This is applied to each resource contained in the
endpoint's response.