Conditional requests on things

Conditional requests on things enable developers to express that a request should only be applied for the case that some condition is met.

Example: If the attribute key equals 42, set the status of the feature is-fancy to true.

PUT /api/2/things/my.namespace:device-01/features/is-fancy/properties/status/?condition=eq(attributes/key,42) 
    true

Bosch IoT Things supports modifying, deleting, and retrieving things based on specific conditions of the current thing state.

Conditions are based on RQL expressions and define that a request should be applied to a thing only if the condition is true. All fields of the thing can be used to define the condition.

E.g. you can use a timestamp in case you only want to change the state of the thing, if the provided value is newer than in the last state of the thing.

  • If the condition specified in the request is fulfilled, the thing will be updated and an event will be emitted.
  • If the condition specified in the request is not fulfilled, the thing is not modified, and no event/change notification is emitted.

Conditional requests are supported via HTTP API, WebSocket, Ditto protocol and Ditto Java Client.

Permissions

The requester needs READ and WRITE permission on the resource which is requested, otherwise the request will fail. For the specified condition it is necessary to have READ permission.

Examples

The following sections will show how to use conditional requests via the HTTP API, the Ditto protocol, and the Ditto Java Client.

To demonstrate the new conditional request, we assume that the following thing already exists:

{
  "thingId": "my.namespace:coffeebrewer",
  "policyId": "my.namespace:coffeebrewer-policy",
  "definition": "org.eclipse.ditto:coffeebrewer:0.1.0",
  "attributes": {
    "manufacturer": "ACME demo corp.",
    "location": "Wonderland",
    "serialno": "42",
    "model": "Speaking coffee machine"
  },
  "features": {
    "coffee-brewer": {
      "definition": ["org.eclipse.ditto:coffeebrewer:0.1.0"],
      "properties": {
        "brewed-coffees": 0
      }
    },
    "water-tank": {
      "properties": {
        "configuration": {
          "smartMode": true,
          "brewingTemp": 87,
          "tempToHold": 44.5,
          "timeoutSeconds": 6000
        },
        "status": {
          "waterAmount": 731,
          "temperature": 44.2,
          "lastModified": "2021-09-23T07:01:56Z"
        }
      }
    }
  }
}

Condition based on last modification

In this example the water-tanks’s temperature should only be updated if it was lastModified after “2021-09-23T07:01:56Z “.

Permissions to execute the example

For this example, the authorized subject could have READ and WRITE permissions on the complete thing resource. However, it is only necessary on the path thing/features/water-tank/properties/status, because the temperature as well as the conditional part lastModified are located there.

Conditional requests via HTTP API

Using the HTTP API the condition can either be specified via HTTP Header or via HTTP query parameter.
In this section, we will show how to use both options.

Conditional request with HTTP Header

curl -X PATCH -H 'Content-Type: application/json' -H 'condition: gt(features/water-tank/properties/status/lastModified,"2021-09-23T07:00:00Z")' /api/2/things/my.namespace:coffeebrewer/features/water-tank/properties/properties/temperature -d '{ temperature: 45.26, "lastModified": "'"$(date +%Y-%m-%dT%H:%M:%S)"'" }'

Conditional request with HTTP query parameter

curl -X PATCH -H 'Content-Type: application/json' /api/2/things/my.namespace:coffeebrewer/features/water-tank/properties/status/temperature?condition=gt(features/water-tank/properties/status/lastModified,"2021-09-23T07:00:00Z") -d '{ temperature: 45.26, "lastModified": "'"$(date +%Y-%m-%dT%H:%M:%S)"'" }'

Result

After the request was successfully performed, the thing will look like this:

{
  "thingId": "my.namespace:coffeebrewer",
  "policyId": "my.namespace:coffeebrewer-policy",
  "definition": "org.eclipse.ditto:coffeebrewer:0.1.0",
  "attributes": {
    "manufacturer": "ACME demo corp.",
    "location": "Wonderland",
    "serialno": "42",
    "model": "Speaking coffee machine"
  },
  "features": {
    "coffee-brewer": {
      "definition": ["org.eclipse.ditto:coffeebrewer:0.1.0"],
      "properties": {
        "brewed-coffees": 0
      }
    },
    "water-tank": {
      "properties": {
        "configuration": {
          "brewingTemp": 87,
          "tempToHold": 44.5,
          "timeoutSeconds": 6000
        },
        "status": {
          "waterAmount": 731,
          "temperature": 45.26,
          "lastModified": "2021-09-23T07:15:24Z"
        }
      }
    }
  }
}

Conditional request via Ditto protocol

It is also possible to use conditional requests via the Ditto protocol. Applying the following Ditto command to the existing thing will lead to the same result as in the above HTTP example.

{
  "topic": "my.namespace/coffeebrewer/things/twin/commands/modify",
  "headers": {
    "content-type": "application/json",
    "condition": "gt(features/water-tank/properties/status/lastModified,\"2021-09-23T07:00:00Z\")"
  },
  "path": "/features/water-tank/properties/status/temperature",
  "value": 45.26
}

Using conditional requests in the Ditto Java Client

The conditional requests are also supported via the Ditto Java Client starting with the version 2.1.0.

Example for a conditional update of a thing with the ditto-client:

final String THING_ID = "my.namespace:coffeebrewer";
final String FEATURE_ID = "water-tank";
final Feature FEATURE = ThingsModelFactory.newFeatureBuilder()
        .properties(ThingsModelFactory.newFeaturePropertiesBuilder()
            .set("status", JsonFactory.newObjectBuilder()
                .set("temperature", 45.26)
                .set("lastModified", Instant.now())
                .build())
            .build())
        .withId(FEATURE_ID)
        .build();

final Thing THING = ThingsModelFactory.newThingBuilder()
        .setId(THING_ID)
        .setFeature(FEATURE)
        .build();

// initialize the ditto-client
final DittoClient dittoClient = ... ;

dittoClient.twin().update(THING, Options.Modify.condition("gt(features/water-tank/properties/status/lastModified,"2021-09-23T07:00:00Z")")).
        .whenComplete(((adaptable, throwable) -> {
            if (throwable != null) {
                LOGGER.error("Received error while sending conditional update: '{}' ", throwable.toString());
            } else {
                LOGGER.info("Received response for conditional update: '{}'", adaptable);
            }
        }));

After running this code snippet, the existing thing should look like the above result for the HTTP example.

Further reading

See HTTP API - Search resources for all Relational operators and Logical operators.
Find details on RQL expressions in Eclipse Ditto: https://www.eclipse.org/ditto/basic-rql.html.

tip See additionally the ETag approach described in our FAQ section.

Corporate information Data protection notice Legal information Support Free plans