HttpCalls
In this article we will talk about EDDI's
httpCalls
feature (calling other JSON
APIs).The
httpCalls
feature allows a Chatbot to consume 3rd party APIs and use the JSON
response in another httpCall
(for authentication or requesting a token for instance) or directly print the results in Chatbot's Output,
this means, for example, you can call a weather API and use the JSON
response in your Chatbot's output if the user asks about today's weather or the week's forecast!We will emphasize the
httpCall
model and go through an example step by step, you can also download the example in Postman collection format and run the steps.{
"targetServerUrl": "string",
"httpCalls": [
{
"name": "string",
"saveResponse": boolean,
"fireAndForget": boolean,
"responseObjectName": "string",
"actions": [
"string"
],
"preRequest": {
"batchRequests": {
"pathToTargetArray": "string",
"iterationObjectName": "string"
}
},
"request": {
"path": "string",
"headers": {},
"queryParams": {},
"method": "string",
"contentType": "string",
"body": "string"
},
"postResponse": {
"qrBuildInstruction": {
"pathToTargetArray": "String",
"iterationObjectName": "String",
"quickReplyValue": "String",
"quickReplyExpressions": "String"
},
"propertyInstructions": [
{
"name": "string",
"value": "string",
"scope": "string",
"fromObjectPath": "savedObjName.something.something",
"override": boolean,
"httpCodeValidator": {
"runOnHttpCode": [
<array of Integers>
],
"skipOnHttpCode": [
<array of Integers>
]
}
}
]
}
}
]
}
An
httpCall
is mainly composed from the targetServer
array
of httpCalls
, the latter will have request where you put all details about your actual http request (method
,path
,headers
, etc..) and postResponse where you can define what happens after the httpCall
has been executed and a response
has been received; such as quick replies by using qrBuildInstruction
.You can use
${memory.current.httpCalls.<responseObjectName>}
to access your JSON
object, so you can use it in output templating
or in another httpCall
, for example an httpCall
will get the oAuth
token
and another httpCall
will use in the http
headers
to authenticate to an API.Element | Description |
targetServerUrl | ( String ) root/context path of the httpCall (e.g http://example.com/api) |
httpCall.saveResponse | ( Boolean ) whether to save the JSON response into ${memory.current.httpCalls} |
httpCall.fireAndForget | ( Boolean ) whether to execute the request without waiting for a response to be returned, (useful for POST ) |
httpCall.responseObjectName | ( String ) name of the JSON object so it can be accessed from other httpCalls or outputsets . |
httpCall.actions | ( String ) name of the output /behavior set mapped to this http call. |
httpCall.preRequest.batchRequests.pathToTargetArray | ( String ) JSON path to the target array to be used as body of requests e.g: "memory.current.output " |
httpCall.preRequest.batchRequests.iterationObjectName | ( String ) name of the variable to be used for each element of array found in pathToTargetArray |
httpCall.request.path | ( String ) path in the targetServer of the httpCall (e.g /books ) |
httpCall.request.headers | ( Array :<key, value> ) for each httpCall HTTP header |
httpCall.request.queryParams | ( Array : <key, value>) for each httpCall query parameter |
httpCall.request.method | ( String ) HTTP Method of the httpCall (e.g GET ,POST ,etc...) |
httpCall.request.contentType | ( String ) value of the contentType HTTP header of the httpCall |
httpCall.request.body | ( String ) an escaped JSON object that goes in the HTTP Request body if needed. |
httpCall.postResponse.qrBuildInstruction.pathToTargetArray | ( String ) path to the array in your JSON response data. |
httpCall.postResponse.qrBuildInstruction.iterationObjectName | ( String ) a variable name that will point to the TargetArray. |
httpCall.postResponse.qrBuildInstruction.quickReplyValue | ( String ) thymeleaf expression to use as a quickReply value. |
httpCall.postResponse.qrBuildInstruction.quickReplyExpressions | ( String ) expression to retrieve a property from iterationObjectName . |
httpCall.postResponse.propertyInstructions.name | ( String ) name of property to be used in templating |
httpCall.postResponse.propertyInstructions.value | ( String ) a static value can be set here if fromObjectPath is not defined. |
httpCall.postResponse.propertyInstructions.scope | ( String ) Can be either : step used for only for one user interaction conversation for entire conversation and longTerm for between conversations |
httpCall.postResponse.propertyInstructions.fromObjectPath | ( String ) JSON path to the saved object e.g savedObjName.something.something |
httpCall.postResponse.propertyInstructions.override | ( Boolean ) flag for override |
httpCall.postResponse.propertyInstructions.httpCodeValidator.runOnHttpCode | ( Array : <Integer> ) a list of http code that enables this property instruction e.g [200 ] |
httpCall.postResponse.propertyInstructions.httpCodeValidator.skipOnHttpCode | ( Array : <Integer>) list of http code that enables this property instruction e.g [500,501,400 ] |
HTTP Method | API Endpoint | Request Body | Response |
POST | /httpcallsstore/httpcalls | http-call-model | N/A |
GET | /httpcallsstore/httpcalls/descriptors | N/A | list of references to http-call-model |
DELETE | /httpcallsstore/httpcalls/{id} | N/A | N/A |
GET | /httpcallsstore/httpcalls/{id} | N/A | http-call-model |
PUT | /httpcallsstore/httpcalls/{id} | http-call-model | N/A |
GET | /httpcallsstore/httpcalls/{id}/currentversion | N/A | http-call-model |
POST | /httpcallsstore/httpcalls/{id}/currentversion | http-call-model | N/A |
{
"targetServerUrl": "https://api.bot-metrics.com/v1/messages",
"httpCalls": [
{
"name": "sendUserMessageToAnalytics",
"actions": [
"send_input_to_analytics"
],
"saveResponse": false,
"fireAndForget": true,
"request": {
"method": "post",
"queryParams": {
"token": "<token>"
},
"contentType": "application/json",
"body": "{\"text\": \"[[${memory.current.input}]]\",\"message_type\": \"incoming\",\"user_id\": \"[[${memory.current.userInfo.userId}]]\",\"platform\": \"eddi\"}"
}
},
{
"name": "sendBotMessageToAnalytics",
"actions": [
"send_output_to_analytics"
],
"saveResponse": false,
"fireAndForget": true,
"preRequest": {
"batchRequests": {
"pathToTargetArray": "memory.current.output",
"iterationObjectName": "output"
}
},
"request": {
"method": "post",
"queryParams": {
"token": "<token>"
},
"contentType": "application/json",
"body": "{\"text\": \"[[${output}]]\",\"message_type\": \"outgoing\",\"user_id\": \"[[${memory.current.userInfo.userId}]]\",\"platform\": \"eddi\"}"
},
"postResponse": {
"propertyInstructions": [
{
"name": "nameOfPropertyToBeUsedInTemplating",
"value": "StaticValueHereIfFromObjectPathIsNotDefined",
"scope": "step",
"fromObjectPath": "savedObjName.something.something",
"override": true,
"httpCodeValidator": {
"runOnHttpCode": [
200
],
"skipOnHttpCode": [
0,
400,
401,
402,
403,
404,
409,
410,
500,
501,
502
]
},
"qrBuildInstruction": {
"pathToTargetArray": "savedObjName.data.topics",
"iterationObjectName": "topic",
"templateFilterExpression": "${topic.subType} != 'specialSubType'",
"quickReplyValue": "[(${topic.name})]",
"quickReplyExpressions": "property(topic_id([(${topic.id})]))"
}
}
]
}
}
]
}
We will do a step by step example from scratch (Chatbot creation to a simple conversation that uses
httpCall
)For the sake of simplicity we will use a free weather API to fetch weather of cities by their names (api.openweathermap.org).
Request URL
POST
http://localhost:7070/regulardictionarystore/regulardictionaries
Request Body
{
"words": [
{
"word": "weather",
"expressions": "trigger(current_weather)",
"frequency": 0
}
],
"phrases": [
{
"phrase": "what is the weather",
"expressions": "trigger(current_weather)"
},
{
"phrase": "whats the weather",
"expressions": "trigger(current_weather)"
}
]
}
Response Body
no content
Response Code
201
Response Headers
{
"access-control-allow-origin": "*",
"date": "Sun, 13 May 2018 16:40:58 GMT",
"access-control-allow-headers": "authorization, Content-Type",
"content-length": "0",
"location": "eddi://ai.labs.regulardictionary/regulardictionarystore/regulardictionaries/5af86a9aba31c023bcb9ef2b?version=1",
"access-control-allow-methods": "GET, PUT, POST, DELETE, PATCH, OPTIONS",
"access-control-expose-headers": "location",
"content-type": null
}
Request URL
POST
http://localhost:7070/behaviorstore/behaviorsets
Response Body
no content
Response Code
201
Request Body
{
"behaviorGroups": [
{
"name": "",
"behaviorRules": [
{
"name": "Ask for City",
"actions": [
"ask_for_city"
],
"conditions": [
{
"type": "inputmatcher",
"configs": {
"expressions": "trigger(current_weather)"
}
}
]
},
{
"name": "Current Weather in City",
"actions": [
"current_weather_in_city"
],
"conditions": [
{
"type": "inputmatcher",
"configs": {
"expressions": "trigger(current_weather)",
"occurrence": "lastStep"
}
}
]
}
]
}
]
}
Response Headers
{
"access-control-allow-origin": "*",
"date": "Sun, 13 May 2018 16:45:52 GMT",
"access-control-allow-headers": "authorization, Content-Type",
"content-length": "0",
"location": "eddi://ai.labs.behavior/behaviorstore/behaviorsets/5af86bc0ba31c023bcb9ef2c?version=1",
"access-control-allow-methods": "GET, PUT, POST, DELETE, PATCH, OPTIONS",
"access-control-expose-headers": "location",
"content-type": null
}
Note that we can pass user input to the http call using
[[${memory.current.input}]]
Request URL
POST
http://localhost:7070/httpcallsstore/httpcalls
Request Body
{
"targetServerUrl": "https://api.openweathermap.org/data/2.5/weather",
"httpCalls": [
{
"name": "currentWeather",
"saveResponse": true,
"responseObjectName": "currentWeather",
"actions": [
"current_weather_in_city"
],
"request": {
"path": "",
"headers": {},
"queryParams": {
"APPID": "c3366d78c7c0f76d63eb4cdf1384ddbf",
"units": "metric",
"q": "[[${memory.current.input}]]"
},
"method": "get",
"contentType": "",
"body": ""
}
}
]
}
Response Body
no content
Response Code
201
Response Headers
{
"access-control-allow-origin": "*",
"date": "Sun, 13 May 2018 19:13:52 GMT",
"access-control-allow-headers": "authorization, Content-Type",
"content-length": "0",
"location": "eddi://ai.labs.httpcalls/httpcallsstore/httpcalls/5af88e70ba31c023bcb9ef2e?version=1",
"access-control-allow-methods": "GET, PUT, POST, DELETE, PATCH, OPTIONS",
"access-control-expose-headers": "location",
"content-type": null
}
Note When you set"saveResponse" : true
inhttpCall
then you can use[[${memory.current.httpCalls.<responseObjectName>}]]
to access the response data and usethymeleaf
(th:each
) to iterate overJSON
arrays
if you have them in yourJSON
response.
Request URL
POST
http://localhost:7070/outputstore/outputsets
Request Body
{
"outputSet": [
{
"action": "ask_for_city",
"timesOccurred": 0,
"outputs": [
{
"valueAlternatives": [
{
"type": "text",
"text": "Which City would you like to know the weather of?"
}
]
}
]
},
{
"action": "current_weather_in_city",
"timesOccurred": 0,
"outputs": [
{
"valueAlternatives": [
{
"type": "text",
"text": "The current weather situation of [[${memory.current.input}]] is [[${memory.current.httpCalls.currentWeather.weather[0].description}]] at [[${memory.current.httpCalls.currentWeather.main.temp}]] °C"
}
]
}
]
}
]
}
Response Body
no content
Response Code
201
Response Headers
{
"access-control-allow-origin": "*",
"date": "Sun, 13 May 2018 16:48:37 GMT",
"access-control-allow-headers": "authorization, Content-Type",
"content-length": "0",
"location": "eddi://ai.labs.output/outputstore/outputsets/5af86c65ba31c023bcb9ef2d?version=1",
"access-control-allow-methods": "GET, PUT, POST, DELETE, PATCH, OPTIONS",
"access-control-expose-headers": "location",
"content-type": null
}
Important Package note
ai.labs.httpcalls
&ai.labs.output
must come afterai.labs.behavior
in order of the package definitionai.labs.templating
has to be afterai.labs.output
Request URL
POST
http://localhost:7070/packagestore/packages
Request Body
{
"packageExtensions": [
{
"type": "eddi://ai.labs.parser",
"extensions": {
"dictionaries": [
{
"type": "eddi://ai.labs.parser.dictionaries.integer"
},
{
"type": "eddi://ai.labs.parser.dictionaries.decimal"
},
{
"type": "eddi://ai.labs.parser.dictionaries.punctuation"
},
{
"type": "eddi://ai.labs.parser.dictionaries.email"
},
{
"type": "eddi://ai.labs.parser.dictionaries.time"
},
{
"type": "eddi://ai.labs.parser.dictionaries.ordinalNumber"
},
{
"type": "eddi://ai.labs.parser.dictionaries.regular",
"config": {
"uri": "eddi://ai.labs.regulardictionary/regulardictionarystore/regulardictionaries/{{dictionary_id}}?version=1"
}
}
],
"corrections": [
{
"type": "eddi://ai.labs.parser.corrections.stemming",
"config": {
"language": "english",
"lookupIfKnown": "false"
}
},
{
"type": "eddi://ai.labs.parser.corrections.levenshtein",
"config": {
"distance": "2"
}
},
{
"type": "eddi://ai.labs.parser.corrections.mergedTerms"
}
]
},
"config": {}
},
{
"type": "eddi://ai.labs.behavior",
"config": {
"uri": "eddi://ai.labs.behavior/behaviorstore/behaviorsets/{{behaviourset_id}}?version=1"
}
},
{
"type": "eddi://ai.labs.httpcalls",
"config": {
"uri": "eddi://ai.labs.httpcalls/httpcallsstore/httpcalls/{{httpcall_id}}?version=1"
}
},
{
"type": "eddi://ai.labs.output",
"config": {
"uri": "eddi://ai.labs.output/outputstore/outputsets/{{outputset_id}}?version=1"
}
},
{
"type": "eddi://ai.labs.templating",
"extensions": {},
"config": {}
}
]
}
Response Body
no content
Response Code
201
Response Headers
{
"access-control-allow-origin": "*",
"date": "Sun, 13 May 2018 19:26:36 GMT",
"access-control-allow-headers": "authorization, Content-Type",
"content-length": "0",
"location": "eddi://ai.labs.package/packagestore/packages/5af8916cba31c023bcb9ef2f?version=1",
"access-control-allow-methods": "GET, PUT, POST, DELETE, PATCH, OPTIONS",
"access-control-expose-headers": "location",
"content-type": null
}
Request URL
POST
http://localhost:7070/botstore/bots
Request Body
{
"packages": [
"eddi://ai.labs.package/packagestore/packages/{{package_id}}?version=1"
],
"channels": []
}
Response Body
no content
Response Code
201
Response Headers
{
"access-control-allow-origin": "*",
"date": "Sun, 13 May 2018 21:18:16 GMT",
"access-control-allow-headers": "authorization, Content-Type",
"content-length": "0",
"location": "eddi://ai.labs.bot/botstore/bots/5af8ab98ba31c023bcb9ef32?version=1",
"access-control-allow-methods": "GET, PUT, POST, DELETE, PATCH, OPTIONS",
"access-control-expose-headers": "location",
"content-type": null
}
Request URL
POST
http://localhost:7070/administration/restricted/deploy/**<bot_id>**?version=1&autoDeploy=true
Response Body
no content
Response Code
202
Response Headers
{
"access-control-allow-origin": "*",
"date": "Sun, 13 May 2018 21:21:54 GMT",
"access-control-allow-headers": "authorization, Content-Type",
"content-length": "0",
"access-control-allow-methods": "GET, PUT, POST, DELETE, PATCH, OPTIONS",
"access-control-expose-headers": "location",
"content-type": null
}
Request URL
POST
http://localhost:7070/bots/**<env>**/**<bot_id>**
Response Body
no content
Response Code
201
Response Headers
{
"access-control-allow-origin": "*",
"date": "Sun, 13 May 2018 21:30:45 GMT",
"access-control-allow-headers": "authorization, Content-Type",
"content-length": "0",
"location": "eddi://ai.labs.conversation/conversationstore/conversations/5af8ae85ba31c023bcb9ef35",
"access-control-allow-methods": "GET, PUT, POST, DELETE, PATCH, OPTIONS",
"access-control-expose-headers": "location",
"content-type": null
}
Request URL
POST
http://localhost:7070/bots/<env>/<bot_id>/<conversation_id>?returnDetailed=false&returnCurrentStepOnly=true
Request Body
{
"input": "weather"
}
Response Body
{
"botId": "5af8b075ba31c023bcb9ef3b",
"botVersion": 1,
"environment": "unrestricted",
"conversationState": "READY",
"redoCacheSize": 0,
"conversationSteps": [
{
"conversationStep": [
{
"key": "input:initial",
"value": "weather"
},
{
"key": "actions",
"value": [
"ask_for_city"
]
},
{
"key": "output:text:ask_for_city",
"value": "Which City would you like to know the weather of?"
}
],
"timestamp": 1526247548410
}
]
}
Response Code
200
Response Headers
{
"access-control-allow-origin": "*",
"date": "Sun, 13 May 2018 21:35:15 GMT",
"content-type": "application/json;resteasy-server-has-produces=true",
"access-control-allow-headers": "authorization, Content-Type",
"content-length": "325",
"access-control-allow-methods": "GET, PUT, POST, DELETE, PATCH, OPTIONS",
"access-control-expose-headers": "location"
}
Request URL
POST
http://localhost:7070/bots/<env>/<bot_id>/<conversation_id>?returnDetailed=false&returnCurrentStepOnly=true
Request Body
{
"botId": "5af8b075ba31c023bcb9ef3b",
"botVersion": 1,
"environment": "unrestricted",
"conversationState": "READY",
"redoCacheSize": 0,
"conversationSteps": [
{
"conversationStep": [
{
"key": "input:initial",
"value": "Vienna"
},
{
"key": "actions",
"value": [
"current_weather_in_city"
]
},
{
"key": "output:text:current_weather_in_city",
"value": "The current weather situation of Vienna is clear sky at 17.68 °C"
}
],
"timestamp": 1526247618080
}
]
}
Response Code
200
Response Headers
{
"access-control-allow-origin": "*",
"date": "Sun, 13 May 2018 21:35:15 GMT",
"content-type": "application/json;resteasy-server-has-produces=true",
"access-control-allow-headers": "authorization, Content-Type",
"content-length": "325",
"access-control-allow-methods": "GET, PUT, POST, DELETE, PATCH, OPTIONS",
"access-control-expose-headers": "location"
}
If you would like to run the full example through postman, you can download and import the collection below.
EDDI - Weather bot.postman_collection.json
21KB
Code
EDDI - Weather bot.postman_collection.json
Last modified 1yr ago