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.
Shows us what Focus Areas there are in CS
What modules are associated with the respective Focus Areas
Retrieve information about the module
First, import the following packages
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
TOKEN: Final = '' # NEVER SHARE THIS PUBLICLY
We create an immutable list with each sublist representing a focus area
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?

In this instance, we set {acadYear} as 2023-2024, and the user will input their module code.
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
Define the the function
Create the Keyboard via a 2D list of of
InLineKeyboardButton
objects -> The number ofInLineKeyboardButton()
elements in a sublist represents the number of buttons in a row
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)
Inline Keyboard Markup that displays how the keyboard is displayed
Sending the message
"Please choose a focus area: "
reply_markup = InlineKeyboardMarkup(keyboard)
await update.message.reply_text(text="Please choose a focus area: ", reply_markup=reply_markup)
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()
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
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)
Explanation
query = update.callback_query
Retrieve the callback query (info) from the update (i.e. the button the user clicked on)
await query.answer()
Informs telegram that the query has been received
focus_area_primaries = get_primaries(query.data)
Obtains the text of primaries based on data from
query
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.
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
Last updated