{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "bc1715f8-62de-41d7-855b-e85095669e3f",
   "metadata": {},
   "source": [
    "# Application Programming Interfaces\n",
    "\n",
    "APIs sind Schnittstellen die einem Programmier erlauben mit Systemen zu hantieren ohne diese Selbständig verändern zu müssen. Ein bekanntes Beispiel für APIs sind Datenbank Systeme, welche meist nicht direkt sondern von Programmen bedient werden. Dazu sendet das Programm eine Nachricht bsp. __SELECT Person FROM Staff__ und die Datenbank antwort mit allen _Persondaten_ aus der Tabelle _Staff_.\n",
    "\n",
    "Folgendes Prinzip lässt sich auf (Python-)Bibliotheken, Datenbanken, Webseiten und dergleichen mit einigen Unterschieden anwenden."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "67120b98-6899-4ace-85c8-0de7a8d4d1bc",
   "metadata": {},
   "source": [
    "## Protokolle\n",
    "\n",
    "Wer schonmal in die Adresszeile seines handelsüblichen Browsers geschaut hat dem wird auffallen das vor der Domain ein _https://_ steht. Dies ist die Angabe des Protokolls. Protokolle sind dazu da eine standartisierte Kommunikationsschnittstelle aufzubauen mit der beide Clienten hantieren können.\n",
    "\n",
    "Spezifizierungen einfügen\n",
    "\n",
    "### HTTP(S)\n",
    "\n",
    "_**H**yper**t**ext **T**ransfer **P**rotocol (**S**ecure)_ ist ein Protokoll zum Übertragen von HTML _(**H**yper**t**ext **M**arkup **L**anguage)_ Dateien über das Web. Das _Secure_ im Namen steht nur dafür das der Kommunikationskanal, jedoch nicht die Datei selbst, verschlüsselt ist.\n",
    "\n",
    "### SMTP\n",
    "\n",
    "_**S**imple **M**ail **T**ransfer **P**rotocol_ ist das standard übertragungsprotokoll von E-Mails.\n",
    "\n",
    "### (s)FTP\n",
    "\n",
    "_(**S**ecure) **F**ile **T**ransfer **P**rotocol_ ist ein Protokoll zum Übertragen von Dateien zwischen zwei Servern. Auch hier steht das _Secure_ nur für einen verschlüsselten Übertragungskanal, meist realisiert über das _ssh_ Protokoll."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5751c64a",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-05d72e9ca62b39b3",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "## Web APIs\n",
    "\n",
    "Im folgenden behandeln wir die Benutzung von _Web APIs_. Dazu verwenden wir die _Speiseplan API_ des _Studentenwerks OstNiedersachsens_.\n",
    "\n",
    "Dazu stellen wir mittels Python HTTP Request an die API und verarbeiten die Daten."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5a43fc69-f61c-4de6-8045-567b37c1d9c6",
   "metadata": {},
   "source": [
    "## URL\n",
    "\n",
    "Wie gerade angekündigt verwenden wir das Hypertext Transfer Protocol zum abrufen der Daten. Dies setzt vorraus, dass das Prinzip einer URL verstanden wurde.\n",
    "\n",
    "Schreiben wir also das jahr 1994 im Dezember und versetzen uns in die Lage der _Internet Engineering Task Force_ zum standatisieren von Resourcen Auffrufen in verteilten Rechnersystemen. Mit dem Standard [RFC 1738](https://datatracker.ietf.org/doc/rfc1738/) wurde die _URL (Unified Resourde Locators)_ geboren, welche 2023 von dem Standard [RFC 3986](https://datatracker.ietf.org/doc/rfc3986/) _URI (Uniform Resource Identifier)_ abgelöst wurde.\n",
    "\n",
    "_URLs_ sind ein Teil der neuen _URIs_.\n",
    "\n",
    "### Aufbau einer URL\n",
    "\n",
    "Jede URL hat folgenden Aufbau:\n",
    "\n",
    "> < scheme > : < scheme-specific-part >\n",
    "\n",
    "_scheme_ legt fest welche Methode zum abrufen der Resource verwendet wird. (Bsp. HTTP)\n",
    "\n",
    "_scheme-specific-part_ beschreibt spezifischen Parameter die für das angewandte Protokoll verwendet werden\n",
    "\n",
    "Beispiel HTTP:\n",
    "\n",
    "Für das _scheme_ benötingt wird _http://_ oder _https://_ verwendet. _://_ trennt das _scheme_ vom Spezifischen Part.\n",
    "\n",
    "Optional, für einige APIs notwendig kann jetzt ein Nutzername und Passwort angegeben werden getrennt durch ein _:_ und mit _@_ an die Domain angehängt:\n",
    "\n",
    "```\n",
    "< user >_< password >@< domain >\n",
    "```\n",
    "\n",
    "Notwendig ist der nächste für die meisten Bekannte teil der Host oder Domain.\n",
    "Dieser kann als _IPv4_ (Bsp. 178.160.4.2), _IPv6_ (Bsp. 2065::8800) oder _Domainname_ (Bsp. www.tu-braunschweig.de) angegeben werden.\n",
    "\n",
    "Damit erhält man im Normalfall bereits eine funktionierende Adresse:\n",
    "\n",
    "> https://www.tu-braunschweig.de/\n",
    "\n",
    "Die Standardkommunikationskanäle für _HTTP_ & _HTTPS_ sind _80 (HTTP)_ und _443 (HTTPS)_. URL erlaubt aber die Spezifizierung eines abiträren Ports bei eingabe der URL. Dies kann nützlich sein wenn API zugriffe auf anderen Ports passieren sollen oder Dienste auch Sicherheitsgründen bewusst von den Standardports getrennt werden. Gültige Portnummer liegen in dem Bereich von 0 bis 65.535 (=2^16-1). Für das Beispiel wird Port 9090 verwendet. \n",
    "\n",
    "> e.g.: http://example.com:9090/\n",
    "\n",
    "Damit auch bestimmte Dateien angesprochen werden können unterstützt HTTP die möglichkeit Pfade anzugeben. Der Standardpfad von Webseiten ist meist eine _/index.html_. Der Pfad kann aber auch auf Unterordner des Webservers bzw. der Resource zugreifen.\n",
    "\n",
    "> e.g.: http://example.com/directory1/directory2/file.txt\n",
    "\n",
    "HTTP unterstützt (ähnlich wie Datenbanken) eine _Query_ anfrage. Dazu wird mittels _?_ ein oder mehrere Parameter übergeben. Dazu spezifiziert man erst das abzufragende Attribut (im beispiel _user_) und übergibt diesem einen Wert (im beispiel _=peter_). Mehrere Parameter werden durch _&_ getrennt.\n",
    "\n",
    "> e.g.: http://example.com/api?user=peter&age=30\n",
    "\n",
    "HTML Seiten unterstützen _Fragmente_ oder _Kapitel_, diese Werden angegeben mit _#_.\n",
    "\n",
    "> e.g.: http://example.com/document.html#site3\n",
    "\n",
    "Daraus ergibt sich nach Spezifizierung folgendes abstraktes Modell für HTTP:\n",
    "\n",
    "```\n",
    "http(s)://<user>:<password>@<host>:<port>/<location>/<document>?<paramter_n>=<value_n>#<fragment>\n",
    "```\n",
    "\n",
    "> e.g.: http://peter:1234@example.com:9090/files/users.html?user=peter&age=30#livestory"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "40ec9940-0991-4a5a-983c-2dafb6d711e9",
   "metadata": {},
   "source": [
    "## JavaScript Object Notation\n",
    "\n",
    "![](https://upload.wikimedia.org/wikipedia/commons/c/c9/JSON_vector_logo.svg)\n",
    "\n",
    "(kurz: JSON) 1997 von Douglas Crockford unter [RFC 8529](https://datatracker.ietf.org/doc/html/rfc4627#section-2) spezifiert, ist ein einfach lesbares Textformat zum austauschen von Daten. Es unterstüzt verschiedene Datentypen zum Austausch wie folgende Tabelle Zeigt:\n",
    "\n",
    "| Type      | Value                       | Explanation                                                                |\n",
    "|-----------|-----------------------------|----------------------------------------------------------------------------|\n",
    "| Nullvalue | _null_                      | Describes a Key without any Value                                          |\n",
    "| Boolean   | _true_ or _false_           | These aren't Strings!                                                      |\n",
    "| Number    | _42_ or _-12.5_ or _3.4e12_ | Describes a Number                                                         |\n",
    "| String    | _\"This is a String\"_        | Just a normal String. Behold _true_ is a Boolean and _\"true\"_ is a String. |\n",
    "| Array     | _[42, \"best Number\", true]_ | A collection of data can hold mixed Types                                  |\n",
    "\n",
    "Um ein JSON Objekt zu beschreiben wird es in _{ }_ eingekapselt und folgt einem _< Key >:< Value >_ Konzept, bei dem jedem Wert ein Schlüssel zugeordnet wird. Der Schlüssel muss innerhalb eines Objektes immer eindeutig sein und wird als String, also in Anführungszeichen _\" \"_ angegeben. Schlüssel-Werte-Paare werden mit _,_ getrennt. Bsp.:\n",
    "\n",
    "```json\n",
    "{\n",
    "    \"Number\": 42,\n",
    "    \"Question\": \"What is the answer to everything?\",\n",
    "    \"ComputeTime\": 3.4e6,\n",
    "    \"finished\": true,\n",
    "    \"Interns\": [\"Arthur\", \"Ford\", \"Zhapod\", \"Trillian\"]\n",
    "    \"UnnecessaryNestedObject\": \n",
    "    {\n",
    "         \"UnnecessaryNestedObject\": \n",
    "        {\n",
    "             \"UnnecessaryNestedObject\": \n",
    "            {\n",
    "                 \"UnnecessaryNestedObject\": \n",
    "                {\n",
    "                    \"kEy\": null\n",
    "                }   \n",
    "            }   \n",
    "        }   \n",
    "    }\n",
    "}\n",
    "\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0e63b343-032c-40d5-ab7e-3ba89a4e1bf9",
   "metadata": {},
   "source": [
    "## Python Datetime"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "46189b02-922c-49f3-8afc-e8d52975261d",
   "metadata": {},
   "source": [
    "## Stundentenwerk Mensa API\n",
    "\n",
    "Die Dokumentation zur Mensa API befindet sich unter https://api.stw-on.de/#einfuhrung"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "96308adb",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-e23c74ac6f2b9827",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "## Basic Example\n",
    "\n",
    "For making the calls to the API, we will use the very popular [requests](https://requests.readthedocs.io/en/latest/) library.\n",
    "It allows to perform HTTP requests, which we need to get the latest menu."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "6538d76c",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-685a30ab750c3f6c",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "import requests"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d7459fea",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-4d486b0abefc44d3",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "An example of an API endpoint that can be used to request the menu for a particular Mensa and week is given in the `API_URL_EXAMPLE`.\n",
    "(Try opening that website in your browser and see what happens.)\n",
    "\n",
    "You will need to adapt this in the following to request the menu for multiple Mensas and varying weeks."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "dd43eaee",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-4a82b88787cce066",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'https://sls.api.stw-on.de/v1/location/101/menu/2023-07-17/2023-07-27'"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from datetime import date, timedelta\n",
    "today = date.today()\n",
    "\n",
    "API_URL_EXAMPLE = \"https://sls.api.stw-on.de/v1/location/101/menu/{}/{}\".format(today - timedelta(days=10), today)\n",
    "\n",
    "API_URL_EXAMPLE\n",
    "\n",
    "# Hint Mensa-Codes:\n",
    "# Mensa 1: 101\n",
    "# Mensa 2: 105\n",
    "# 360: 111"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1eb40e52",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-b7ec4ca409f5ac01",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "The actual request is done using the `requests.get` command.\n",
    "This basically returns the content that you can also see when opening the link in your browser.\n",
    "\n",
    "Since the returned value is in the [JSON](https://en.wikipedia.org/wiki/JSON) format, we need to use the `.json()` function to grab it.\n",
    "\n",
    "As you might have noticed already, the JSON format looks very similar to the dictionary structure in Python. Therefore, the output of the `.json()` function is a dictionary, from which we only need the `meals` key."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "827cc9c2",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-dd3e78d210747035",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[{'date': '2023-07-24',\n",
      "  'id': 35099,\n",
      "  'lane': {'id': 10, 'name': 'Suppe & Co.', 'name_en': 'Soup & Co.'},\n",
      "  'location': {'address': {'city': 'Braunschweig',\n",
      "                           'line1': 'Mensa 1 TU Braunschweig',\n",
      "                           'line2': None,\n",
      "                           'street': 'Katharinenstraße 1',\n",
      "                           'zip': '38106'},\n",
      "               'id': 101,\n",
      "               'name': 'Mensa 1 TU Braunschweig',\n",
      "               'opening_hours': [{'end_day': 4,\n",
      "                                  'end_time': '14:30:00',\n",
      "                                  'start_day': 1,\n",
      "                                  'start_time': '11:30:00',\n",
      "                                  'time': 'noon'},\n",
      "                                 {'end_day': 5,\n",
      "                                  'end_time': '14:00:00',\n",
      "                                  'start_day': 5,\n",
      "                                  'start_time': '11:30:00',\n",
      "                                  'time': 'noon'},\n",
      "                                 {'end_day': 0,\n",
      "                                  'end_time': '00:00:14',\n",
      "                                  'start_day': 0,\n",
      "                                  'start_time': '00:00:11',\n",
      "                                  'time': 'noon'}]},\n",
      "  'name': 'Die Mensa 1 ist vom 24.07.2023 bis 11.08.2023 geschlossen. Ab dem '\n",
      "          '14.08.2023 sind wir wieder für Euch da.',\n",
      "  'name_en': 'Die Mensa 1 ist vom 24.07.2023 bis 11.08.2023 geschlossen. Ab '\n",
      "             'dem 14.08.2023 sind wir wieder für Euch da.',\n",
      "  'nutritional_values': {'_NOTE': 'WARNING: These fields currently contain '\n",
      "                                  'incorrect values. Do not use them yet!',\n",
      "                         'per_100_grams': {'caloric_value': None,\n",
      "                                           'carbohydrates': None,\n",
      "                                           'fat': None,\n",
      "                                           'protein': None,\n",
      "                                           'roughage': None,\n",
      "                                           'salt': None,\n",
      "                                           'saturated_fatty_acids': None,\n",
      "                                           'sugar': None}},\n",
      "  'price': {'employee': '0.00', 'guest': '0.00', 'student': '0.00'},\n",
      "  'special_tags': ['Deprecated. Use tags→special instead.'],\n",
      "  'tags': {'additives': [], 'allergens': [], 'categories': [], 'special': []},\n",
      "  'time': 'noon'},\n",
      " {'date': '2023-07-25',\n",
      "  'id': 35100,\n",
      "  'lane': {'id': 10, 'name': 'Suppe & Co.', 'name_en': 'Soup & Co.'},\n",
      "  'location': {'address': {'city': 'Braunschweig',\n",
      "                           'line1': 'Mensa 1 TU Braunschweig',\n",
      "                           'line2': None,\n",
      "                           'street': 'Katharinenstraße 1',\n",
      "                           'zip': '38106'},\n",
      "               'id': 101,\n",
      "               'name': 'Mensa 1 TU Braunschweig',\n",
      "               'opening_hours': [{'end_day': 4,\n",
      "                                  'end_time': '14:30:00',\n",
      "                                  'start_day': 1,\n",
      "                                  'start_time': '11:30:00',\n",
      "                                  'time': 'noon'},\n",
      "                                 {'end_day': 5,\n",
      "                                  'end_time': '14:00:00',\n",
      "                                  'start_day': 5,\n",
      "                                  'start_time': '11:30:00',\n",
      "                                  'time': 'noon'},\n",
      "                                 {'end_day': 0,\n",
      "                                  'end_time': '00:00:14',\n",
      "                                  'start_day': 0,\n",
      "                                  'start_time': '00:00:11',\n",
      "                                  'time': 'noon'}]},\n",
      "  'name': 'Die Mensa 1 ist vom 24.07.2023 bis 11.08.2023 geschlossen. Ab dem '\n",
      "          '14.08.2023 sind wir wieder für Euch da.',\n",
      "  'name_en': 'Die Mensa 1 ist vom 24.07.2023 bis 11.08.2023 geschlossen. Ab '\n",
      "             'dem 14.08.2023 sind wir wieder für Euch da.',\n",
      "  'nutritional_values': {'_NOTE': 'WARNING: These fields currently contain '\n",
      "                                  'incorrect values. Do not use them yet!',\n",
      "                         'per_100_grams': {'caloric_value': None,\n",
      "                                           'carbohydrates': None,\n",
      "                                           'fat': None,\n",
      "                                           'protein': None,\n",
      "                                           'roughage': None,\n",
      "                                           'salt': None,\n",
      "                                           'saturated_fatty_acids': None,\n",
      "                                           'sugar': None}},\n",
      "  'price': {'employee': '0.00', 'guest': '0.00', 'student': '0.00'},\n",
      "  'special_tags': ['Deprecated. Use tags→special instead.'],\n",
      "  'tags': {'additives': [], 'allergens': [], 'categories': [], 'special': []},\n",
      "  'time': 'noon'},\n",
      " {'date': '2023-07-26',\n",
      "  'id': 35101,\n",
      "  'lane': {'id': 10, 'name': 'Suppe & Co.', 'name_en': 'Soup & Co.'},\n",
      "  'location': {'address': {'city': 'Braunschweig',\n",
      "                           'line1': 'Mensa 1 TU Braunschweig',\n",
      "                           'line2': None,\n",
      "                           'street': 'Katharinenstraße 1',\n",
      "                           'zip': '38106'},\n",
      "               'id': 101,\n",
      "               'name': 'Mensa 1 TU Braunschweig',\n",
      "               'opening_hours': [{'end_day': 4,\n",
      "                                  'end_time': '14:30:00',\n",
      "                                  'start_day': 1,\n",
      "                                  'start_time': '11:30:00',\n",
      "                                  'time': 'noon'},\n",
      "                                 {'end_day': 5,\n",
      "                                  'end_time': '14:00:00',\n",
      "                                  'start_day': 5,\n",
      "                                  'start_time': '11:30:00',\n",
      "                                  'time': 'noon'},\n",
      "                                 {'end_day': 0,\n",
      "                                  'end_time': '00:00:14',\n",
      "                                  'start_day': 0,\n",
      "                                  'start_time': '00:00:11',\n",
      "                                  'time': 'noon'}]},\n",
      "  'name': 'Die Mensa 1 ist vom 24.07.2023 bis 11.08.2023 geschlossen. Ab dem '\n",
      "          '14.08.2023 sind wir wieder für Euch da.',\n",
      "  'name_en': 'Die Mensa 1 ist vom 24.07.2023 bis 11.08.2023 geschlossen. Ab '\n",
      "             'dem 14.08.2023 sind wir wieder für Euch da.',\n",
      "  'nutritional_values': {'_NOTE': 'WARNING: These fields currently contain '\n",
      "                                  'incorrect values. Do not use them yet!',\n",
      "                         'per_100_grams': {'caloric_value': None,\n",
      "                                           'carbohydrates': None,\n",
      "                                           'fat': None,\n",
      "                                           'protein': None,\n",
      "                                           'roughage': None,\n",
      "                                           'salt': None,\n",
      "                                           'saturated_fatty_acids': None,\n",
      "                                           'sugar': None}},\n",
      "  'price': {'employee': '0.00', 'guest': '0.00', 'student': '0.00'},\n",
      "  'special_tags': ['Deprecated. Use tags→special instead.'],\n",
      "  'tags': {'additives': [], 'allergens': [], 'categories': [], 'special': []},\n",
      "  'time': 'noon'},\n",
      " {'date': '2023-07-27',\n",
      "  'id': 35102,\n",
      "  'lane': {'id': 10, 'name': 'Suppe & Co.', 'name_en': 'Soup & Co.'},\n",
      "  'location': {'address': {'city': 'Braunschweig',\n",
      "                           'line1': 'Mensa 1 TU Braunschweig',\n",
      "                           'line2': None,\n",
      "                           'street': 'Katharinenstraße 1',\n",
      "                           'zip': '38106'},\n",
      "               'id': 101,\n",
      "               'name': 'Mensa 1 TU Braunschweig',\n",
      "               'opening_hours': [{'end_day': 4,\n",
      "                                  'end_time': '14:30:00',\n",
      "                                  'start_day': 1,\n",
      "                                  'start_time': '11:30:00',\n",
      "                                  'time': 'noon'},\n",
      "                                 {'end_day': 5,\n",
      "                                  'end_time': '14:00:00',\n",
      "                                  'start_day': 5,\n",
      "                                  'start_time': '11:30:00',\n",
      "                                  'time': 'noon'},\n",
      "                                 {'end_day': 0,\n",
      "                                  'end_time': '00:00:14',\n",
      "                                  'start_day': 0,\n",
      "                                  'start_time': '00:00:11',\n",
      "                                  'time': 'noon'}]},\n",
      "  'name': 'Die Mensa 1 ist vom 24.07.2023 bis 11.08.2023 geschlossen. Ab dem '\n",
      "          '14.08.2023 sind wir wieder für Euch da.',\n",
      "  'name_en': 'Die Mensa 1 ist vom 24.07.2023 bis 11.08.2023 geschlossen. Ab '\n",
      "             'dem 14.08.2023 sind wir wieder für Euch da.',\n",
      "  'nutritional_values': {'_NOTE': 'WARNING: These fields currently contain '\n",
      "                                  'incorrect values. Do not use them yet!',\n",
      "                         'per_100_grams': {'caloric_value': None,\n",
      "                                           'carbohydrates': None,\n",
      "                                           'fat': None,\n",
      "                                           'protein': None,\n",
      "                                           'roughage': None,\n",
      "                                           'salt': None,\n",
      "                                           'saturated_fatty_acids': None,\n",
      "                                           'sugar': None}},\n",
      "  'price': {'employee': '0.00', 'guest': '0.00', 'student': '0.00'},\n",
      "  'special_tags': ['Deprecated. Use tags→special instead.'],\n",
      "  'tags': {'additives': [], 'allergens': [], 'categories': [], 'special': []},\n",
      "  'time': 'noon'}]\n"
     ]
    }
   ],
   "source": [
    "resp = requests.get(API_URL_EXAMPLE)\n",
    "data = resp.json()\n",
    "\n",
    "from pprint import pprint\n",
    "pprint(data.get(\"meals\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ba34c8a8",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-bd8670a16c01faaf",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "The response object `resp` contains all information about the returned response, e.g., the [status code](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes). This can be accessed using `resp.status_code`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "30c25792",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-8c31ebd06d496e82",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Response Status Code: 200\n",
      "The response is OK\n"
     ]
    }
   ],
   "source": [
    "print(f\"Response Status Code: {resp.status_code:d}\")\n",
    "if resp.status_code == 200:\n",
    "    print(\"The response is OK\")\n",
    "elif resp.status_code == 400:\n",
    "    print(\"Bad request\")\n",
    "elif resp.status_code == 404:\n",
    "    print(\"Page not found\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7f29b034",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-3a85de1510d22a61",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "# Exercise\n",
    "\n",
    "## Task 1\n",
    "\n",
    "wake a response to the Mensa-Api for the timeframe _today - 7 Days_ and _today - 1 Day_."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "id": "87f6c752",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-0b6b462a6367f7f4",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "from datetime import date, timedelta"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "id": "8930b71f",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-08a14df39976e5fd",
     "locked": false,
     "schema_version": 3,
     "solution": true,
     "task": false
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "### BEGIN SOLUTION\n",
    "today = date.today()\n",
    "API_URL = \"https://sls.api.stw-on.de/v1/location/101/menu/{}/{}\".format(today - timedelta(days = 7), today - timedelta(days = 1))\n",
    "resp = requests.get(API_URL)\n",
    "resp_json = resp.json()\n",
    "meals = resp_json.get(\"meals\")\n",
    "### END SOLUTION"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "id": "9f9e52ec",
   "metadata": {
    "nbgrader": {
     "grade": true,
     "grade_id": "cell-547c77541bc7e8d7",
     "locked": true,
     "points": 1,
     "schema_version": 3,
     "solution": false,
     "task": false
    },
    "tags": []
   },
   "outputs": [
    {
     "ename": "AssertionError",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAssertionError\u001b[0m                            Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[76], line 3\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(meals, \u001b[38;5;28mlist\u001b[39m)\n\u001b[1;32m      2\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(meals) \u001b[38;5;241m>\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;241m1\u001b[39m\n\u001b[0;32m----> 3\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m meals[\u001b[38;5;241m0\u001b[39m][\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdate\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m==\u001b[39m \u001b[38;5;28mstr\u001b[39m(today \u001b[38;5;241m-\u001b[39m timedelta(days \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m7\u001b[39m))\n\u001b[1;32m      4\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m meals[\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m][\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdate\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m==\u001b[39m \u001b[38;5;28mstr\u001b[39m(today \u001b[38;5;241m-\u001b[39m timedelta(days \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m1\u001b[39m))\n",
      "\u001b[0;31mAssertionError\u001b[0m: "
     ]
    }
   ],
   "source": [
    "assert isinstance(meals, list)\n",
    "assert len(meals) >= 1\n",
    "assert meals[0]['date'] == str(today - timedelta(days = 7))\n",
    "assert meals[-1]['date'] == str(today - timedelta(days = 1))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f174a34e",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-ed3079a3df502335",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "Now convert the list of meals into a Pandas DataFrame object and store it in `df_meals`.\n",
    "Make sure that the `date` column has the `datetime` data type and that the prices are in a numeric (`float`) format.\n",
    "\n",
    "_Hint:_ You might want to check the [`pandas.json_normalize`](https://pandas.pydata.org/docs/reference/api/pandas.json_normalize.html) function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "id": "cefd8da9",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-9259345eb48b5c8b",
     "locked": false,
     "schema_version": 3,
     "solution": true,
     "task": false
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "### BEGIN SOLUTION ###\n",
    "df_meals = pd.json_normalize(meals)\n",
    "df_meals[\"date\"] = pd.to_datetime(df_meals[\"date\"])\n",
    "df_meals[\"price.student\"] = pd.to_numeric(df_meals[\"price.student\"])\n",
    "### END SOLUTION ###"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "id": "349bfe40",
   "metadata": {
    "nbgrader": {
     "grade": true,
     "grade_id": "cell-7757b771151de7c4",
     "locked": true,
     "points": 1,
     "schema_version": 3,
     "solution": false,
     "task": false
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "assert isinstance(df_meals, pd.DataFrame)\n",
    "assert df_meals['price.student'].dtype == float"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f564dc6c",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-6ac65fd244814f1d",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "Next, create a simple plot that plots the student prices over time. You can use a scatter plot to do this."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "id": "c0d9ebed",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-b407c97934dfeca2",
     "locked": false,
     "schema_version": 3,
     "solution": true,
     "task": false
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.collections.PathCollection at 0x7fe7b80aacd0>"
      ]
     },
     "execution_count": 79,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 13060 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "### BEGIN SOLUTION\n",
    "plt.scatter(df_meals[\"date\"], df_meals[\"price.student\"])\n",
    "### END SOLUTION"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b2f985cc",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-47eead3031d0c7f0",
     "locked": true,
     "schema_version": 3,
     "solution": false,
     "task": false
    }
   },
   "source": [
    "## Task 2\n",
    "\n",
    "Next, make a request to the Mensa API to get all meals in the time frame August 1, 2022 to December 1, 2022.\n",
    "\n",
    "What can you observe?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "id": "dadfc688",
   "metadata": {
    "nbgrader": {
     "grade": false,
     "grade_id": "cell-357c6cd2a43ed307",
     "locked": false,
     "schema_version": 3,
     "solution": true,
     "task": false
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "400\n",
      "{\"error\":{\"code\":400,\"message\":\"Cannot query more than 21 days at once\"}}\n"
     ]
    }
   ],
   "source": [
    "### BEGIN SOLUTION\n",
    "API_URL_2 = \"https://sls.api.stw-on.de/v1/location/101/menu/2022-08-01/2022-12-01\"\n",
    "resp2 = requests.get(API_URL_2)\n",
    "print(resp2.status_code)\n",
    "print(resp2.text)\n",
    "### END SOLUTION"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Create Assignment",
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.12.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
