As you build your conversational app, you will inevitably come to a point where hardcoding responses, variables and entities simply will not be possible, or make sense. You will have to call one, or several, APIs to fetch user information, to make an order reservation. This is typically where other (especially GUI-based) bot creation tools fail and force you to "eject" your app and hand it over to developers in some way.
This is not the case for Narratory, dynamic data and special handling of this is expected and built into the platform and thus jack in perfectly with the conversational design ultimately allowing developers and dialog designers to work side by side.
DynamicBotTurns - Calling APIs in BotTurns
To call an API in a BotTurn, you define your BotTurn as a DynamicBotTurn instead of a normal BotTurn. This will give the turn access to additional parameters:
Notably, for the DynamicBotTurn, the say parameter is optional, it has a mandatory url parameter and an optional params parameter. When the turn is executed, Narratory will call the URL and pass along all parameters that match the names given in the params array. Narratory expects a response with an optional say parameter with a string value or string array, and an optional set parameter with an object of parameters. In other words, the webhook can return a subset of BotTurn parameters. Narratory will wait for the return of the webhook unless you use Async webhooks - Fire and forget.
Important: the say parameter that comes from your API endpoint has priority over the one in the dialog script, allowing you to dynamically override the behavior in your script depending on some backend/business logic.
The following example illustrates a narrative using a DynamicBotTurn to change a variable and set a new one.
In our cloud endpoint, we could do DB lookups, call other APIs or do whatever we want. As noted above, Narratory expects the response to be a JSON object with optional say and set parameters. You can create new variables as you see fit in this fashion.
The below is an example of how an endpoint could look, in NodeJS pseudocode. You could really build this in any language or framework of your (or your developer's) preference. The parameters will be passed as a JSON. Aside from receiving parameters from the script as shown above, the sessionId of the current dialog session is always passed with the call, and can be accessed as below.
The above will result in the following script:
Note, currently you have to provide answers statically in the script, i.e your endpoint can't return an answer-array. This might be implemented at a later point if it is requested from creators. Let us know! :-)
Async webhook calls - fire and forget
Sometimes you might want to do an API-call but the dialog is not dependent on the answer. This could for example be a call do log something or a request that takes longer time to process than you want users to wait in the dialog.
To set a webhook call to asynchronous, you add the flag
asyncWebhook: true (default is false) to the DynamicBotTurn. An example follows:
BridgeTurns, allowing sequencial BotTurns
In some cases, you want to have a BotTurn directly follow another BotTurn in nested dialogs. One example could be if you call an API in a BotTurn (as shown above) and want to handle it differently depending on the reply from the API directly in the BotTurn (as opposed to in the next bot initiative - the top-level BotTurn in Narrative). The reason why you want this is, for example, to be able to use repair to let the user try again if the API response comes back with a failed reply. An example of this follows:
Above, if the user presents an order number that the API finds valid, the API returns an order variable and the dialog continues. If the API doesn't reply an order however, the bot gives the user another chance. BridgeTurns really shine in this context, but can also be used in the top-level, e.g. to do conditional greetings in one turn instead of several.
For example, instead of using several turns for serving returning and new users as shown here:
... you can instead write it more condensed: