In this article we will talk about EDDI's httpCalls feature.
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 http call model and go through an example step by step, you can also download the example in POSTMAN collection format and run the steps.
{ "targetServer": "string", "httpCalls": [ { "name": "string", "saveResponse": true, "responseObjectName": "string", "actions": [ "string" ], "request": { "path": "string", "headers": {}, "queryParams": {}, "method": "string", "contentType": "string", "body": "string" }, "postResponse": { "qrBuildInstruction": { "pathToTargetArray": "String", "iterationObjectName": "String", "quickReplyValue": "String", "quickReplyExpressions": "String" } } } ] } |
an http call 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 ${memory.current.httpCalls.<responseObjectName>} to access your JSON object, so you can use it in output templating or in another http call, for example an http call will get the oAuth token and another http call will use in the http headers to authenticate to an api.
targetServer | (String ) root/context path of the http call (e.g http://example.com/api) |
---|---|
httpCall.saveResponse | (Boolean ) whether to save the json response into ${memory.current.httpCalls} |
httpCall.responseObjectName | (String ) name of the json object so it can be accessed from other http calls or outputsets. |
httpCall.actions | (String ) name of the output/behavior set mapped to this http call. |
httpCall.request.path | (String ) path of the http call (e.g /books) |
httpCall.request.headers | (String: key,value ) for each http call header |
httpCall.request.queryParams | (String: key,value ) for each http call query parameter |
httpCall.request.method | (String ) Http method of the http call (e.g GET,POST,etc...) |
httpCall.request.contentType | (String ) value of the contentType header of the http call |
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 quick reply value. |
httpCall.postResponse.qrBuildInstruction.quickReplyExpressions | (String ) expression to retreive a property from iterationObjectName. |
HTTP Method | API Endpoint | Request Body | Response |
---|---|---|---|
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/descriptors | N/A | list of references to http-call-model |
POST | /httpcallsstore/httpcalls | 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 |
We will do a step by step example from scratch (chatbot creation to a simple conversation that uses http call)
For the sake of simplicity we will use a free weather API to fetch weather of cities by their names (api.openweathermap.org)
More about regular dictionaries can be found here .
Request URL POST http://localhost:7070/regulardictionarystore/regulardictionaries Request Body { "words": [ { "word": "weather", "exp": "trigger(current_weather)", "frequency": 0 } ], "phrases": [ { "phrase": "what is the weather", "exp": "trigger(current_weather)" }, { "phrase": "whats the weather", "exp": "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 } |
More about behaviorSets can be found here.
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" ], "children": [ { "type": "inputmatcher", "values": { "expressions": "trigger(current_weather)" }, "children": [] } ] }, { "name": "Current Weather in City", "actions": [ "current_weather_in_city" ], "children": [ { "type": "inputmatcher", "values": { "expressions": "trigger(current_weather)", "occurrence": "lastStep" }, "children": [] } ] } ] } ] } 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 { "targetServer" : "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 } |
More about outputSet can be found here.
When you set "saveResponse" : true in http call then you can use [[${memory.current.httpCalls.<responseObjectName>}]] to access the response data and use thymeleaf( th:each ) to iterate over JSON arrays if you have them in your JSON response. |
Request URL POST http://localhost:7070/outputstore/outputsets Request Body { "outputSet": [ { "action": "ask_for_city", "timesOccurred": 0, "outputs": [ { "type": "text", "valueAlternatives": [ "Which City would you like to know the weather of?" ] } ], "quickReplies": [] }, { "action": "current_weather_in_city", "timesOccurred": 0, "outputs": [ { "type": "text", "valueAlternatives": [ "The current weather situation of [[${memory.current.input}]] is [[${memory.current.httpCalls.currentWeather.weather[0].description}]] at [[${memory.current.httpCalls.currentWeather.main.temp}]] °C" ] } ], "quickReplies": [] } ] } 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 } |
More about packages can be found here.
|
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 { "input":"Vienna" } Response 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.