# Buggy code
async def parse_apiai(opsdroid, message, config):
    """Parse a message against all apiai skills."""
    # pylint: disable=broad-except
    # We want to catch all exceptions coming from a skill module and not
    # halt the application. If a skill throws an exception it just doesn't
    # give a response to the user, so an error response should be given.
    if "access-token" in config:
        result = await call_apiai(message, config)

        if result["status"]["code"] >= 300:
            _LOGGER.error(
                "api.ai error - "
                + str(result["status"]["code"])
                + " "
                + result["status"]["errorType"]
            )
            return

        if "min-score" in config and result["result"]["score"] < config["min-score"]:
            _LOGGER.debug("api.ai score lower than min-score")
            return

        if result:
            for skill in opsdroid.skills:
                if "apiai_action" in skill or "apiai_intent" in skill:
                    if (
                        "action" in result["result"]
                        and skill["apiai_action"] in result["result"]["action"]
                    ) or (
                        "intentName" in result["result"]
                        and skill["apiai_intent"] in result["result"]["intentName"]
                    ):
                        message.apiai = result
                        try:
                            await skill["skill"](opsdroid, skill["config"], message)
                        except Exception:
                            await message.respond("Whoops there has been an error")
                            await message.respond("Check the log for details")
                            _LOGGER.exception(
                                "Exception when parsing '"
                                + message.text
                                + "' against skill '"
                                + result["result"]["action"]
                                + "'"
                            )


# Traceback (aiohttp.client_exceptions.ClientConnectorError)
ERROR asyncio: Task exception was never retrieved
future: <Task finished coro=<parse_apiai() done, defined at /Users/jacob/Projects/opsdroid/opsdroid/opsdroid/parsers/apiai.py:34> exception=ClientConnectorError(8, 'Cannot connect to host api.api.ai:443 ssl:True [nodename nor servname provided, or not known]')>
Traceback (most recent call last):
File "/Users/jacob/Projects/opsdroid/opsdroid/venv/lib/python3.6/site-packages/aiohttp/connector.py", line 375, in connect
proto = yield from self._create_connection(req)
File "/Users/jacob/Projects/opsdroid/opsdroid/venv/lib/python3.6/site-packages/aiohttp/connector.py", line 632, in _create_connection
_, proto = yield from self._create_direct_connection(req)
File "/Users/jacob/Projects/opsdroid/opsdroid/venv/lib/python3.6/site-packages/aiohttp/connector.py", line 643, in _create_direct_connection
hosts = yield from self._resolve_host(req.url.raw_host, req.port)
File "/Users/jacob/Projects/opsdroid/opsdroid/venv/lib/python3.6/site-packages/aiohttp/connector.py", line 615, in _resolve_host
self._resolver.resolve(host, port, family=self._family)
File "/Users/jacob/Projects/opsdroid/opsdroid/venv/lib/python3.6/site-packages/aiohttp/resolver.py", line 30, in resolve
host, port, type=socket.SOCK_STREAM, family=family)
File "/opt/boxen/homebrew/Cellar/python3/3.6.0/Frameworks/Python.framework/Versions/3.6/lib/python3.6/concurrent/futures/thread.py", line 55, in run
result = self.fn(*self.args, **self.kwargs)
File "/opt/boxen/homebrew/Cellar/python3/3.6.0/Frameworks/Python.framework/Versions/3.6/lib/python3.6/socket.py", line 743, in getaddrinfo
for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
socket.gaierror: [Errno 8] nodename nor servname provided, or not known

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "/Users/jacob/Projects/opsdroid/opsdroid/opsdroid/parsers/apiai.py", line 42, in parse_apiai
result = await call_apiai(message, config)
File "/Users/jacob/Projects/opsdroid/opsdroid/opsdroid/parsers/apiai.py", line 27, in call_apiai
headers=headers)
File "/Users/jacob/Projects/opsdroid/opsdroid/venv/lib/python3.6/site-packages/aiohttp/client.py", line 621, in __await__
resp = yield from self._coro
File "/Users/jacob/Projects/opsdroid/opsdroid/venv/lib/python3.6/site-packages/aiohttp/client.py", line 225, in _request
conn = yield from self._connector.connect(req)
File "/Users/jacob/Projects/opsdroid/opsdroid/venv/lib/python3.6/site-packages/aiohttp/connector.py", line 380, in connect
.format(key, exc.strerror)) from exc
aiohttp.client_exceptions.ClientConnectorError: [Errno 8] Cannot connect to host api.api.ai:443 ssl:True [nodename nor servname provided, or not known]

# Fixed code
async def parse_apiai(opsdroid, message, config):
    """Parse a message against all apiai skills."""
    # pylint: disable=broad-except
    # We want to catch all exceptions coming from a skill module and not
    # halt the application. If a skill throws an exception it just doesn't
    # give a response to the user, so an error response should be given.
    if "access-token" in config:
        try:
            result = await call_apiai(message, config)
        except aiohttp.ClientOSError:
            _LOGGER.error("No response from api.ai, check your network.")
            return

        if result["status"]["code"] >= 300:
            _LOGGER.error(
                "api.ai error - "
                + str(result["status"]["code"])
                + " "
                + result["status"]["errorType"]
            )
            return

        if "min-score" in config and result["result"]["score"] < config["min-score"]:
            _LOGGER.debug("api.ai score lower than min-score")
            return

        if result:
            for skill in opsdroid.skills:
                if "apiai_action" in skill or "apiai_intent" in skill:
                    if (
                        "action" in result["result"]
                        and skill["apiai_action"] in result["result"]["action"]
                    ) or (
                        "intentName" in result["result"]
                        and skill["apiai_intent"] in result["result"]["intentName"]
                    ):
                        message.apiai = result
                        try:
                            await skill["skill"](opsdroid, skill["config"], message)
                        except Exception:
                            await message.respond("Whoops there has been an error")
                            await message.respond("Check the log for details")
                            _LOGGER.exception(
                                "Exception when parsing '"
                                + message.text
                                + "' against skill '"
                                + result["result"]["action"]
                                + "'"
                            )