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"
}
}
```
!!! note
In the example, `tags` refers to [device groups](../../Devices/Associations/DeviceGroupsOverview.md).
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](https://jsonata.org/) 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](https://graphql.org/), because you can express what the response should contain and how it is shaped.
The API provides transform support only for the [`FetchDevice`](https://api.nrfcloud.com/v1/#operation/FetchDevice) and [`ListDevices`](https://api.nrfcloud.com/v1/#operation/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`:
```bash
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 associated with your account, 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 anid
andtype
property, which return as values for fields of the same name. You can give the field any name you want, such asdeviceId
anddeviceType
. - 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
.
Note
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.