# Integrating API's

If you are a CS student, you may start to think about the different Focus Areas and what you may want to take.

Let's create a telebot that does the following.

1. Shows us what Focus Areas there are in CS
2. What modules are associated with the respective Focus Areas
3. Retrieve information about the module

**First, import the following packages**

```python
import asyncio
import nest_asyncio
from typing import Final
from telegram import (Update, InlineKeyboardButton, InlineKeyboardMarkup)
from telegram.ext import (Application, CallbackQueryHandler, CommandHandler,
                          MessageHandler, filters, ContextTypes)
from telegram.constants import ParseMode
import requests

nest_asyncio.apply()
```

**Next, we replace the Token with our unique token ID**

```python
TOKEN: Final = '' # NEVER SHARE THIS PUBLICLY
```

We create an immutable list with each sublist representing a focus area

```python
PRIMARIES_LIST: Final = [
    ['CS3230', 'CS3231', 'CS3236', 'CS4231', 'CS4234'],            # Algo
    ['CS2109S', 'CS3263', 'CS3264', 'CS4243', 'CS4246', 'CS4248'], # AI
    ['CS3241', 'CS3242', 'CS3247', 'CS4247', 'CS4350'],            # Games
    ['CS2107', 'CS3235', 'CS4236', 'CS4230', 'CS4238', 'CS4239'],  # Security
    ['CS2102', 'CS3223', 'CS4221', 'CS4224', 'CS4225'],            # Database
    ['CS2108', 'CS3245', 'CS4242', 'CS4248', 'CS4347'],            # MIR
    ['CS2105', 'CS3103', 'CS4222', 'CS4226', 'CS4231'],            # Networks
    ['CS3210', 'CS3211', 'CS4231', 'CS4223'],                      # Parallel
    ['CS2104', 'CS3211', 'CS4212', 'CS4215'],                      # Languages
    ['CS2103T', 'CS3213', 'CS3219', 'CS4211', 'CS4218', 'CS4239']  # SWE
]
```

We will make use of the NUSMods API: <https://api.nusmods.com/v2/>

If I want the query the title of a module from the module code, how would I do this?

<figure><img src="https://2807223923-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FTUqAJOgHs57S8lmqdxRV%2Fuploads%2FRUGFvZ01vehN70nK4eSH%2Fimage.png?alt=media&#x26;token=84e00a8b-42cc-4b0c-9626-82605d987a51" alt=""><figcaption></figcaption></figure>

In this instance, we set {acadYear} as 2023-2024, and the user will input their module code.

```python
def get_mod_title(module_code: str) -> str:
    endpoint = f'https://api.nusmods.com/v2/2023-2024/'
                                 f'modules/{module_code}.json'
    response = requests.get(endpoint)
    description = response.json()
    title = description['title']
    return title
```

### Inline Keyboard Buttons

Let's say we want to see all the focus areas via INLINE KEYBOARD AREAS

1. Define the the function
2. Create the Keyboard via a 2D list of of `InLineKeyboardButton`objects\
   ->  The number of `InLineKeyboardButton()` elements in a sublist represents the number of buttons in a row

{% code overflow="wrap" %}

```python
async def focusarea(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:

    keyboard = [
        [   # 4 Buttons in a row
            InlineKeyboardButton(text="Algo & Theory", callback_data="Algorithms and Theory"),
            InlineKeyboardButton(text="AI", callback_data="Artificial Intelligence"),
            InlineKeyboardButton(text="G & G", callback_data="Computer Graphics and Games"),
        ],
        [
            InlineKeyboardButton(text="Security", callback_data="Computer Security"),
            InlineKeyboardButton(text="DB", callback_data="Database Systems"),
            InlineKeyboardButton(text="MIR", callback_data="Multimedia Information Retrieval"),
        ],
        [   # 4 buttons in a row
            InlineKeyboardButton(text="Networks", callback_data="Networking and Distributed Systems"),
            InlineKeyboardButton(text="Parallel", callback_data="Parallel Computing"),
            InlineKeyboardButton(text="Prog Langs", callback_data="Programming Languages"),
            InlineKeyboardButton(text="SWE", callback_data="Software Engineering"),
        ]
    ]

    reply_markup = InlineKeyboardMarkup(keyboard)

    await update.message.reply_text(text="Please choose a focus area: ", reply_markup=reply_markup)

```

{% endcode %}

3. Inline Keyboard Markup that displays how the keyboard is displayed
4. Sending the message `"Please choose a focus area: "`

<pre class="language-python" data-overflow="wrap"><code class="lang-python"><strong>    reply_markup = InlineKeyboardMarkup(keyboard)
</strong><strong>    
</strong><strong>    await update.message.reply_text(text="Please choose a focus area: ", reply_markup=reply_markup)
</strong></code></pre>

**The user clicks on one of the buttons.**

We want the message to change and reflect the user's chosen focus area and it's primaries. Let's create a helper function `get_primaries()`

* Note: we have previously created a function `get_primaries_text()`

```python
def get_primaries(focus_area_title: str) -> str:
    primaries_list = []
    match focus_area_title:
        case "Algorithms and Theory":
            primaries_list = PRIMARIES_LIST[0]
        case "Artificial Intelligence":
            primaries_list = PRIMARIES_LIST[1]
        case "Computer Graphics and Games":
            primaries_list = PRIMARIES_LIST[2]
        case "Computer Security":
            primaries_list = PRIMARIES_LIST[3]
        case "Database Systems":
            primaries_list = PRIMARIES_LIST[4]
        case "Multimedia Information Retrieval":
            primaries_list = PRIMARIES_LIST[5]
        case "Networking and Distributed Systems":
            primaries_list = PRIMARIES_LIST[6]
        case "Parallel Computing":
            primaries_list = PRIMARIES_LIST[7]
        case "Programming Languages":
            primaries_list = PRIMARIES_LIST[8]
        case "Software Engineering":
            primaries_list = PRIMARIES_LIST[9]
        case _:
            primaries_list = []

    return get_primaries_text(primaries_list)
```

**Create the `display_focus_area()` function**

{% code overflow="wrap" %}

```python
async def display_focus_area(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    # The Inline Keyboard Provides a Callback Query that waits for the user's answer
    query = update.callback_query
    await query.answer()

    # Obtains the primaries text based on the data provided by the Query
    focus_area_primaries = get_primaries(query.data)

    # Changes the 'Please select' message to:
    await query.edit_message_text(text=f"Selected option: <b>{query.data}</b>\n"
                                       f"Enter '(MODULE_CODE)' to find out more:\n\n"
                                       f"Primaries: \n{focus_area_primaries}",
                                  parse_mode=ParseMode.HTML)
```

{% endcode %}

**Explanation**

* <pre class="language-python" data-full-width="false"><code class="lang-python">query = update.callback_query
  </code></pre>

  Retrieve the callback query (info) from the update (i.e. the button the user clicked on)<br>

* ```python
   await query.answer()
  ```

  Informs telegram that the query has been received<br>

* ```python
  focus_area_primaries = get_primaries(query.data)
  ```

  Obtains the text of primaries based on data from `query`

* ```python
  await query.edit_message_text(text=f"Selected option: <b>{query.data}</b>\n"
                                         f"Enter '(MODULE_CODE)' to find out more:\n\n"
                                         f"Primaries: \n{focus_area_primaries}",
                                    parse_mode=ParseMode.HTML)
  ```

  Changes the original message that contained the inline keyboard to\
  \
  ->  Show the user's selected option in bold\
  ->  Prompt the user to enter a module code\
  ->  Show the primary modules in that focus area

**The user inputs a module code.**

```python
def display_module(module_json) -> str:
    # Extract fields from the JSON object
    module_code = module_json.get('moduleCode', 'N/A')
    module_title = module_json.get('title', 'No Title')
    module_description = module_json.get('description', 'No Description')
    module_credits = module_json.get('moduleCredit', 'N/A')
    module_prereqs = module_json.get('prerequisite', 'None')
    module_sems = ", ".join(map(str, module_json.get('semesterData', [])))

    # Construct the message
    message = f'{module_code} {module_title}\n'
    message += f'{module_credits} MCs awarded\n'
    message += f'Semesters: {module_sems}\n'
    message += f'Prerequisites: {module_prereqs}\n'
    message += f'\nAbout: {module_description}\n'

    return message
```

<br>
