{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Error Handling Example\n", "\n", "This script shows how handle errors occurring\n", "during API calls to the\n", "Vibration service\n", "\n", "The MVG design principle is that\n", "the client application using the MVG\n", "API is responsible for error handling." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "ExecuteTime": { "end_time": "2021-03-18T10:13:43.989073Z", "start_time": "2021-03-18T10:13:43.956943Z" } }, "outputs": [], "source": [ "import json\n", "import os\n", "import sys\n", "import logging\n", "\n", "# import mvg library with python bindings to mvg-API\n", "from mvg import MVG\n", "from mvg.exceptions import MVGAPIError" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ".. note:: Each `TOKEN` is used both for authorization and authentication. Thus, each unique token represents a unique user and each user has their own unique database on the VA-MVG' service.\n", "\n", "**You need to insert your token received from Viking Analytics here:**" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "ExecuteTime": { "end_time": "2021-03-18T10:13:43.992485Z", "start_time": "2021-03-18T10:13:43.990383Z" }, "tags": [ "parameters" ] }, "outputs": [], "source": [ "TOKEN = os.environ[\"TEST_TOKEN\"] # replace with your token\n", "ENDPOINT = \"https://api.beta.multiviz.com\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is Viking Analytics default logging setup and can be adapted to suit your needs.\n", "Log messages are printed from `mvg` library, see the source code for details." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "ExecuteTime": { "end_time": "2021-03-18T10:13:43.998630Z", "start_time": "2021-03-18T10:13:43.993934Z" } }, "outputs": [], "source": [ "root_logger = logging.getLogger()\n", "root_logger.setLevel(\"INFO\")\n", "formatter = logging.Formatter(\"%(asctime)s - %(levelname)s - %(name)s - %(message)s\")\n", "stream_handler = logging.StreamHandler(stream=sys.stderr)\n", "stream_handler.setFormatter(formatter)\n", "root_logger.addHandler(stream_handler)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As we are interested in error handling we set the logger level to `logging.DEBUG`. That will trace out the detailed information on exceptions provided by the server.\n", "\n", "Set log level to `logging.ERROR` to just see the results of proper error handling in the code `root_logger.setLevel(logging.ERROR)`" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "ExecuteTime": { "end_time": "2021-03-18T10:13:44.004007Z", "start_time": "2021-03-18T10:13:44.000159Z" } }, "outputs": [], "source": [ "root_logger.setLevel(logging.ERROR)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Instantiate a session object with MVG library.\n", "A session object basically catches the endpoint and the token,\n", "to simplify the calls to the MVG library." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "ExecuteTime": { "end_time": "2021-03-18T10:13:44.140140Z", "start_time": "2021-03-18T10:13:44.005184Z" } }, "outputs": [], "source": [ "session = MVG(ENDPOINT, TOKEN)" ] }, { "cell_type": "markdown", "metadata": { "ExecuteTime": { "end_time": "2021-03-04T10:21:42.359990Z", "start_time": "2021-03-04T10:21:42.356703Z" } }, "source": [ "We now check if the server is alive. The hello message contains, amongst others the API version." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "ExecuteTime": { "end_time": "2021-03-18T10:13:44.272280Z", "start_time": "2021-03-18T10:13:44.141278Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{\"name\": \"MultiViz Engine API\", \"version\": \"v0.3.2\", \"swagger\": \"http://api.beta.multiviz.com/docs\"}\n" ] } ], "source": [ "hello_message = json.dumps(session.say_hello())\n", "print(hello_message)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Invalid Token\n", "\n", "Let's provoke an error by creating a session with a non-valid token." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "ExecuteTime": { "end_time": "2021-03-18T10:13:44.395787Z", "start_time": "2021-03-18T10:13:44.273408Z" } }, "outputs": [], "source": [ "unauth_session = MVG(ENDPOINT, \"PASSKEY\")" ] }, { "cell_type": "markdown", "metadata": { "ExecuteTime": { "end_time": "2021-03-04T10:23:13.744955Z", "start_time": "2021-03-04T10:23:13.741660Z" } }, "source": [ "We need to call a method requiring authentication. Check https://api.beta.multiviz.com/docs to see which methods require authentication, they have a lock icon." ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "ExecuteTime": { "end_time": "2021-03-18T10:13:44.549088Z", "start_time": "2021-03-18T10:13:44.397650Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ ">>> Provoke Unathorized call\n", "OUCH\n", "401 - Unauthorized: Unauthorized\n" ] } ], "source": [ "try:\n", " print(\">>> Provoke Unathorized call\")\n", " sources = unauth_session.list_sources()\n", "except MVGAPIError as exc:\n", " # As we have rouge token\n", " # We'll end up here\n", " print(\"OUCH\")\n", " print(exc)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We'll now return to the original session and show how to get details when the server internally rejected a request for other reasons.\n", "\n", "## Illegal source_id\n", "\n", "We provoke the service using an illegal string for the `source_id`." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "ExecuteTime": { "end_time": "2021-03-18T10:13:44.686993Z", "start_time": "2021-03-18T10:13:44.550372Z" }, "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ ">>> Provoke illegal source Id name\n", "OUCH\n", "422 - Unprocessable Entity: [{'loc': ['body', 'source_id'], 'msg': 'string does not match regex \"^[\\\\w-]+$\"', 'type': 'value_error.str.regex', 'ctx': {'pattern': '^[\\\\w-]+$'}}]\n" ] } ], "source": [ "try:\n", " print(\">>> Provoke illegal source Id name\")\n", " session.create_source(\"illegal%name\", channels=[\"acc\"])\n", "except MVGAPIError as exc:\n", " # As we have rouge token\n", " # We'll end up here\n", " print(\"OUCH\")\n", " print(exc)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We'll show a couple of examples what can go wrong when creating a measurement\n", "\n", "## Non-existing Source\n", "\n", "In some cases where there is detailed information provided by the server, we can retrieve it by inspecting the exception object `exc`, which actually contains all information about the request." ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "ExecuteTime": { "end_time": "2021-03-18T10:13:44.829817Z", "start_time": "2021-03-18T10:13:44.688134Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ ">>> Non existing source\n", "404 - Not Found: Not Found\n" ] } ], "source": [ "try:\n", " print(\">>> Non existing source\")\n", " d = [1, 2, 3]\n", " session.create_measurement(sid=\"\",\n", " duration=-3,\n", " timestamp=-5,\n", " data=d,\n", " meta={})\n", "except MVGAPIError as exc:\n", " print(exc)" ] }, { "cell_type": "markdown", "metadata": { "ExecuteTime": { "end_time": "2021-03-04T10:29:35.106386Z", "start_time": "2021-03-04T10:29:35.104168Z" } }, "source": [ "## Parameter Value Out of Range\n", "\n", "Sometimes, it is possible to pass a value that it is out of range of the expected, as in this example where the values for the duration and timestamp parameters are negative values." ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "ExecuteTime": { "end_time": "2021-03-18T10:13:44.968553Z", "start_time": "2021-03-18T10:13:44.831079Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ ">>> Parameter value out of range\n", "422 - Unprocessable Entity: [{'loc': ['body', 0, 'duration'], 'msg': 'ensure this value is greater than 0.0', 'type': 'value_error.number.not_gt', 'ctx': {'limit_value': 0.0}}, {'loc': ['body', 0, 'timestamp'], 'msg': 'ensure this value is greater than or equal to 0', 'type': 'value_error.number.not_ge', 'ctx': {'limit_value': 0}}]\n" ] } ], "source": [ "try:\n", " print(\">>> Parameter value out of range\")\n", " d = {\"acc\": [1, 2, 3]}\n", " session.create_measurement(sid=\"u0001\",\n", " duration=-3,\n", " timestamp=-5,\n", " data=d,\n", " meta={})\n", "except MVGAPIError as exc:\n", " print(exc)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Missing Parameter\n", "\n", "In this case we have an error on the client side.\n", "This means that the data is never sent to the server, so we do not get an `MVGAPIError`, but a `TypeError` instead.\n", "Only the `MVGAPIError` contains any details from the server, so to be on the safe side we should catch them separately." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "ExecuteTime": { "end_time": "2021-03-18T10:13:44.972731Z", "start_time": "2021-03-18T10:13:44.969677Z" }, "pycharm": { "name": "#%%\n" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ ">>> Parameter missing in mvg call\n", "TypeError: create_measurement() missing 1 required positional argument: 'data'\n", "No details from server available\n" ] } ], "source": [ "try:\n", " print(\">>> Parameter missing in mvg call\")\n", " session.create_measurement(sid=\"u0001\",\n", " duration=-3,\n", " timestamp=-5,\n", " meta={})\n", "except MVGAPIError as exc:\n", " print(exc)\n", "except Exception as exc:\n", " print(f\"{type(exc).__name__}: {exc}\")\n", " print(\"No details from server available\")\n" ] } ], "metadata": { "celltoolbar": "Tags", "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.10" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": false, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": true }, "varInspector": { "cols": { "lenName": 16, "lenType": 16, "lenVar": 40 }, "kernels_config": { "python": { "delete_cmd_postfix": "", "delete_cmd_prefix": "del ", "library": "var_list.py", "varRefreshCmd": "print(var_dic_list())" }, "r": { "delete_cmd_postfix": ") ", "delete_cmd_prefix": "rm(", "library": "var_list.r", "varRefreshCmd": "cat(var_dic_list()) " } }, "types_to_exclude": [ "module", "function", "builtin_function_or_method", "instance", "_Feature" ], "window_display": false } }, "nbformat": 4, "nbformat_minor": 2 }