Server Code Triggers

To execute server code automatically, set the information about the server code and the condition in the trigger.

When the server code execution is finished, you can get the execution result (i.e., the returned value and error).

Registering state condition triggers

Before you register a trigger, set the target server code. Refer to Server Extension Programming Guide to learn how you can set the server code.

When you are done with setting the server code, set the endpoint you want to execute by the trigger.

The next example is setting a trigger to execute the alertTemperature endpoint of the server code with the parameter {"caller":"trigger"} when the room temperature goes over 30 degrees.

  • // Specify an end point of server code.
    const accessToken = kii.KiiUser.getCurrentUser().accessToken
    const param = {"caller": "trigger"}
    const serverCode = new ThingIF.ServerCode("myFunction", accessToken, null, param)
    
    // Create a predicate.
    // Execute the server code when the temperature is greater than or equal to 30 deg C.
    const condition = new ThingIF.Condition(ThingIF.Range.greaterThanEquals("currentTemperature", 30));
    const predicate = new ThingIF.StatePredicate(condition, ThingIF.TriggersWhen.CONDITION_FALSE_TO_TRUE);
    
    // Create a trigger request.
    const request = new ThingIF.PostServerCodeTriggerRequest(serverCode, predicate);
    
    // Send a trigger.
    api.postServerCodeTrigger(request).then((trigger: ThingIF.Trigger) => {
      // Do something.
    }).catch((error: ThingIF.ThingIFError) => {
      // Handle the error.
    });
  • // Specify an end point of server code.
    var accessToken = KiiUser.getCurrentUser().accessToken
    var param = {"caller": "trigger"}
    var serverCode = new ThingIF.ServerCode("myFunction", accessToken, null, param)
    
    // Create a predicate.
    // Execute the server code when the temperature is greater than or equal to 30 deg C.
    var condition = new ThingIF.Condition(ThingIF.Range.greaterThanEquals("currentTemperature", 30));
    var predicate = new ThingIF.StatePredicate(condition, ThingIF.TriggersWhen.CONDITION_FALSE_TO_TRUE);
    
    // Create a trigger request.
    var request = new ThingIF.PostServerCodeTriggerRequest(serverCode, predicate);
    
    // Send a trigger.
    api.postServerCodeTrigger(request).then(
      function(trigger) {
        // Do something.
      }
    ).catch(
      function(error) {
        // Handle the error.
      }
    );

In the sample code, we create ServerCode and StatePredicate instances and register a trigger with the postNewTrigger method.

The ServerCode instance is used to set the condition for the server code. We are setting the following parameters in the ServerCode constructor.

  • The first argument: the name of the server code endpoint (i.e., the name of JavaScript function) to execute.
  • The second argument: the access token to be used for executing the server code. We are setting the access token of the owner user in this example. In the server code, you can use the context.getAccessToken() to get the access token of the caller and execute the server code with the privilege of this caller. When you execute the server code with a trigger, the token specified in the argument will be used as the caller token.
  • The third argument: the AppID of the Kii Cloud application that is hosting the server code. If you want to run the server code that is hosted by other application, please specify the AppID of the application here. If the server code is hosted by the same application (i.e., the application specified when you initialize api), you can specify a null value.
  • The fourth argument: the parameter to be passed to the endpoint. You can set a null value if there is no parameter.

The way to initialize the execution condition of the trigger is the same as that of when you initialize a command trigger.

When the trigger is registered, you will get a Trigger instance as a result.

Getting execution results of server code

After setting a trigger, the specified server code will be executed every time when the designated state condition is satisfied. The results are stored in Thing Interaction Framework, and you can check these results via the API.

You can use the pagination if there are many results. If there are 30 results stored in Thing Interaction Framework, for example, you can get 10 results per request (i.e., 10 results per page) and get all results in three requests.

The following is the sample code:

  • const callback = (error: Error, results: ThingIF.QueryResult<ThingIF.ServerCodeResult>)=> {
      if (error) {
        // Handle the error.
        return;
      }
    
      for (const serverCodeResult of results.results) {
        // Check if the server code succeeded or not and process each result.
        if (serverCodeResult.succeeded) {
          const returnedValue: Object = serverCodeResult.returnedValue;
          const executedAt: number = serverCodeResult.executedAt;
          const endpoint: string  = serverCodeResult.endpoint;
        } else {
          const serverError = serverCodeResult.error;
          const errorCode: string = serverError.errorCode;
          const errorMessage: string = serverError.errorMessage;
          const detailMessage: string = serverError.detailMessage;
          const executedAt: number = serverCodeResult.executedAt;
          const endpoint: string  = serverCodeResult.endpoint;
        }
      }
    
      // If the next page exists
      if (results.paginationKey) {
        // Get the next page of the list.
        api.listServerCodeExecutionResults(trigger.triggerID, new ThingIF.ListQueryOptions(null, results.paginationKey), callback);
      }
    };
    
    // Get a list of server code results.
    api.listServerCodeExecutionResults(trigger.triggerID, new ThingIF.ListQueryOptions(10), callback);
  • var callback = function(error, results) {
      if (error) {
        // Handle the error.
        return;
      }
      for (var i = 0; i < results.results.length; i++) {
        var serverCodeResult = results.results[i];
        // Check if the server code succeeded or not and process each result.
        if (serverCodeResult.succeeded) {
          var returnedValue = serverCodeResult.returnedValue;
          var executedAt = serverCodeResult.executedAt;
          var endpoint  = serverCodeResult.endpoint;
        } else {
          var serverError = serverCodeResult.error;
          var errorCode = serverError.errorCode;
          var errorMessage = serverError.errorMessage;
          var detailMessage = serverError.detailMessage;
          var executedAt = serverCodeResult.executedAt;
          var endpoint  = serverCodeResult.endpoint;
        }
      }
    
      // If the next page exists
      if (results.paginationKey) {
        // Get the next page of the list.
        api.listServerCodeExecutionResults(trigger.triggerID, new ThingIF.ListQueryOptions(null, results.paginationKey), callback);
      }
    };
    
    // Get a list of server code results.
    api.listServerCodeExecutionResults(trigger.triggerID, new ThingIF.ListQueryOptions(10), callback);

We are getting the results stored in the server with the listTriggeredServerCodeResults method. As shown in the sample code, we need to set the trigger ID of the target trigger instance. This trigger instance has been returned when you register the trigger to Thing Interaction Framework.

The sample code uses a callback because you need to create a recursive loop structure to get all triggers, though the listServerCodeExecutionResults method supports promises. See the implementation example in Querying KiiObjects to learn how to create a loop with promises.

The second argument of the ListQueryOptions indicates the current page. Calling the listServerCodeExecutionResults method without the pagination key returns the first page and the next pagination key as the paginationKey argument of the callback function. Get the next page by specifying the next pagination key in the next execution of the listServerCodeExecutionResults method. When all results are retrieved, the paginationKey becomes undefined.

The first argument of the ListQueryOptions is the number of results to be retrieved on one page. If you do not specify the argument or set a null value, the value configured on the server side will be automatically used. Commands are retrieved on a best effort basis and you might not be able to get the specified number of results. The results which are not retrieved on a page will be retrieved on a next page.

The list of results is stored in the results argument of the handler. As shown in the sample code, you can check if the execution was a success, the time when the server code was executed, and the endpoint name (function name of the server code). If the execution succeeded, you can get the returned value. If the execution failed, you can get an error message.