Application Programming Interface (API)

API stands for Application Programming Interface. It is a set of rules and protocols that allows different software applications to communicate and interact with each other. An API defines how software components should interact and specifies the methods and data formats to be used for communication.

In simpler terms, an API acts as a bridge between different software systems, enabling them to exchange information and perform specific tasks. It provides a standardised way for developers to access certain functionalities or data of a software application or service without having to understand the underlying implementation details.

APIs can be found in various contexts, including web development, mobile app development, operating systems, and many other software environments. They allow developers to leverage existing functionalities and services by making specific functions or data available for external use. This promotes interoperability and allows developers to build on top of existing software, saving time and effort.

Web APIs, in particular, are commonly used to access web services and retrieve data from remote servers, such as retrieving weather information, accessing social media data, or integrating payment gateways.

Developers interact with APIs by sending requests and receiving responses in a predefined format, such as JSON (JavaScript Object Notation) or XML (eXtensible Markup Language). These requests typically specify the desired action or data, and the API processes the request and returns the appropriate response.

Overall, APIs play a crucial role in modern software development, allowing developers to build upon existing systems, integrate different applications, and create new services by leveraging the functionalities and data exposed through the API interfaces.

# ============================================================
# LESSON: Accessing an API with Python
# API used: REST Countries (https://restcountries.com)
# No sign-up or API key required!
# ============================================================

import urllib.request  # Built-in Python library for making web requests
import json            # Built-in Python library for reading JSON data

# ── STEP 1: Define the API endpoint (the URL we send our request to) ──────────
# This URL asks for ALL countries, but only the fields we care about.
url = "https://restcountries.com/v3.1/all?fields=name,population,area,region"

# ── STEP 2: Send a GET request and read the response ─────────────────────────
print("Contacting the API...")
with urllib.request.urlopen(url) as response:
    raw_data = response.read()           # Raw bytes from the server

# ── STEP 3: Decode the JSON response into a Python list of dictionaries ───────
countries = json.loads(raw_data)         # Each item is one country
print(f"Success! Retrieved data for {len(countries)} countries.\n")

# ── STEP 4: Extract ONE value per country → build a 1D list ──────────────────
# We pull out just the population of each country.
populations = [country["population"] for country in countries]

# Do the same for country names (common name) and regions
names   = [country["name"]["common"] for country in countries]
regions = [country["region"]         for country in countries]

# ── STEP 5: Manipulate the 1D lists ──────────────────────────────────────────
print("=== Basic List Statistics ===")
print(f"Total countries : {len(populations)}")
print(f"Total world pop : {sum(populations):,}")
print(f"Average pop     : {sum(populations) // len(populations):,}")
print(f"Smallest pop    : {min(populations):,}")
print(f"Largest pop     : {max(populations):,}")

# ── STEP 6: Find the country with the largest population ─────────────────────
max_index      = populations.index(max(populations))
most_populated = names[max_index]
print(f"\nMost populated country: {most_populated} ({max(populations):,} people)")

# ── STEP 7: Filter — keep only countries with population > 100 million ────────
big_countries = [names[i] for i in range(len(names)) if populations[i] > 100_000_000]
print(f"\n=== Countries with population > 100 million ({len(big_countries)} total) ===")
for name in sorted(big_countries):
    print(f"  {name}")

# ── STEP 8: Count how many countries are in each region ──────────────────────
print("\n=== Number of Countries per Region ===")
unique_regions = list(set(regions))          # Remove duplicates
unique_regions.sort()

for region in unique_regions:
    count = regions.count(region)            # .count() searches the list
    print(f"  {region:<15} {count} countries")

# ── STEP 9: Your turn! ────────────────────────────────────────────────────────
# Try these challenges:
#   1. Find the country with the SMALLEST non-zero population.
#   2. Build a list of countries in "Oceania" and print them sorted A→Z.
#   3. Calculate the average population of Asian countries only.
#   4. Add "area" to your data and find the country with the highest
#      population DENSITY  (density = population / area).