HttpCalls

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.

Model and API endpoint

{
  "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>
              ]
            }
          }
        ]
      }
    }
  ]
}

Description

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.

Description of the model

HttpCall API endpoints

httpCall Sample

{
  "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})]))"
            }
          }
        ]
      }
    }
  ]
}

Step by step example

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).

1 - Create regularDictionnary

More about regular dictionaries can be found here.

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
}

2 - Create the behaviorSet

More about behaviorSets can be found in Behavior Rules

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
}

3 - Create the httpCall

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
}

4 - Create the outputSet

More about outputSet can be found Output Configuration.

Note When you set "saveResponse" : true in httpCall 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": [
        {
          "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
}

5 - Creating the package

More about packages can be found here.

Important Package note

  • ai.labs.httpcalls & ai.labs.output must come after ai.labs.behavior in order of the package definition

  • ai.labs.templating has to be after ai.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
}

6 - Creating the bot

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
}

7 - Deploy the bot

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
}

8 - Create the conversation

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
}

9 - Say weather

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"
}

10 - Say "Vienna"

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"
}

Full example

If you would like to run the full example through postman, you can download and import the collection below.

Last updated