Python Project: Building a Weather Forecast Application Using APIs

Python Project: Building a Weather Forecast Application Using APIs

Introduction:


In this article, I’ll walk you through a Python project to fetch the 5-day weather forecast for any city using the OpenWeatherMap API. This project showcases how to fetch and handle real-time data from an external API, process it, and present the information in a user-friendly way. The program takes a country/city name as input and displays a detailed 5-day forecast with the date, temperature, and weather description.

These are the steps I took to grasp the concepts:


  1. Understanding APIs: I learned what APIs are and how to make HTTP requests using the requests module.

  2. Getting the API key: I registered on the OpenWeatherMap website and obtained a free API key for accessing weather data. But in your case replace "your_api_key_here" with your key in the program code.

  3. Parsing JSON data: I explored how to handle JSON responses by converting the HTTP response into a Python dictionary using JSON format to extract the required weather details, such as temperature and description.

  4. Formatting timestamps: I used Python’s datetime module to convert and format timestamps into human-readable dates.

  5. Error handling: Implemented error handling to manage invalid API responses or network issues effectively.

  6. Below is the complete Python code :

These are the problems that I encountered:


  1. Using the Wrong API Endpoint for Forecast Data.

  2. Invalid Country / City Names Causing an Error.

  3. Handling Different cod Formats in API Responses.

  4. Time Formatting Issues.

  5. Handling 5-Day Forecast Data with 3-Hour Intervals.

This is how I solved those problems:


1. Using the Wrong API Endpoint for Forecast Data:

Problem:

  • While writing the forecast program initially I used /weather endpoint i.e. current weather data URL which focuses on extracting and printing current weather data, not a forecast.

  • Using this endpoint caused the program to crash because it didn’t return the list key required for processing 5-day forecasts.

# Wrong URL for forecast program i.e using current weather data URL:
base_url = f"http://api.openweathermap.org/data/2.5/weather?q={city}&appid={api_key}&units=metric"

Solution: To fetch multi-day forecasts, I switched to the correct URL for forecast data. Here, the /forecast endpoint returns data for the next 5 days, which includes weather details every 3 hours.

# Correct endpoint for 5-day forecast:
base_url = f"http://api.openweathermap.org/data/2.5/forecast?q={city}&appid={api_key}&units=metric"

2. Invalid Country / City Names Causing an Error:

Problem: When I entered an incorrect country or city name, the program used to get crashed because the API response didn’t include the expected data, leading to a KeyError.

# Example of missing key error
response = requests.get(base_url)
response.raise_for_status()
data = response.json()
print(data["main"]["temp"])  # This will throw a KeyError if the city is invalid

Solution: To fix this, I checked if the API response was successful by verifying the "cod" field in the JSON response. If the "cod" is not equal to "200", the program displays a user-friendly message and stops further execution.

response = requests.get(base_url)
response.raise_for_status()
data = response.json()
if data["cod"] != "200":  # Check if the response is valid
    print(f"City '{city}' not found! Please try again.")
    return

3. Handling Different cod Formats in API Responses:

Problem: One more error I encountered is the cod value in the OpenWeatherMap API response, which indicates the status of the request, it can sometimes be a string ("200") or an integer (200). This inconsistency can cause errors if the condition is written incorrectly, leading to unexpected behavior when checking the API response.

Solution: To handle this problem, first inspect the cod value in the API response by printing data in the output terminal. Then, write the condition to account for both possible formats:

  • Use if data["cod"] != "200": if it’s a string.

  • Use if data["cod"] != 200: if it’s an integer.

Alternatively, you can combine both checks in the condition for a more robust solution.

response = requests.get(base_url)
response.raise_for_status()
data = response.json()
print(data)
if data["cod"] != "200" and data["cod"] != 200:  # Handle cod value inconsistency
    print(f"City '{city}' not found! Please try again.")
    return

4. Time Formatting Issues:

Problem: Initially, I noticed that the weather forecast API provides timestamps in Unix format (numeric representation of time), which are not human-readable. So displaying these timestamps directly made it difficult for me to understand the forecast dates.

# Raw Unix timestamp
timestamp = forecast["dt"]
print(timestamp)  # Outputs something like: 1703260800

Solution: I used Python's datetime module to convert Unix timestamps into readable dates. The datetime.fromtimestamp() function was used to transform the timestamp, and I made it timezone-aware using timezone.utc. Finally, the strftime() method formatted the date into a simple YYYY-MM-DD format for clarity.

from datetime import datetime, timezone

# Converting Unix timestamp to readable date
timestamp = forecast["dt"]
dt_utc = datetime.fromtimestamp(timestamp, timezone.utc)
readable_date = dt_utc.strftime('%Y-%m-%d')  # Formats the date
print(readable_date)  # Outputs something like: 2024-12-23

5. Handling 5-Day Forecast Data with 3-Hour Intervals:

Problem:

  • The OpenWeatherMap API gives weather forecasts for 5 days as default, with updates every 3 hours. This means the data contains 8 entries per day resulting in 40 entries for 5 days, and remember 5 days is default here, thus showing weather details for each 3-hour interval.

  • If we don’t filter this data, the output will be too long and cluttered, showing unnecessary details for every 3 hours instead of summarizing the forecast for each day.

Solution:

To simplify the forecast, I extracted only one data point per day by taking every 8th entry using the slicing method. This way, the program displays one forecast per day, showing the weather details for roughly the same time each day.

# Every 8th entry is for the next day (24 hours)
data["list"][::8]
# Extracting one forecast per day (every 8th entry)
for forecast in data["list"][::8]:
     temp_max = forecast["main"]["temp_max"]
     temp_min = forecast["main"]["temp_min"]
     weather_desc = forecast["weather"][0]["description"]

Output when running in the terminal:


Enter the Country/City name: London
Weather forecast for London:

Date: 2024-12-24
Weather: Overcast clouds
Max Temperature: 8.35°C
Min Temperature: 8.08°C
------------------------------
Date: 2024-12-25
Weather: Overcast clouds
Max Temperature: 8.25°C
Min Temperature: 8.25°C
------------------------------
Date: 2024-12-26
Weather: Clear sky
Max Temperature: 6.68°C
Min Temperature: 6.68°C
------------------------------
Date: 2024-12-27
Weather: Few clouds
Max Temperature: 6.14°C
Min Temperature: 6.14°C
------------------------------
Date: 2024-12-28
Weather: Broken clouds
Max Temperature: 5.23°C
Min Temperature: 5.23°C
------------------------------

Resources:


  • API Website: OpenWeatherMap.

  • Python Modules: requests, datetime, timezone

  • My GitHub Repository with project code - Link