Advertisement
🌤️ Projects

Python Weather App – API Project

Consume the OpenWeatherMap API to get current conditions and forecasts. Teaches API consumption, JSON parsing, and formatted CLI output.

⏱️ 20 min read🎯 Projects📅 Updated 2026

Get API Key

Register at openweathermap.org → API keys. Free tier = 1,000 calls/day.

Complete Implementation

Python
import os, requests
from datetime import datetime

API_KEY = os.getenv("OPENWEATHER_API_KEY", "your_key_here")
BASE = "https://api.openweathermap.org/data/2.5"

def get_current(city, units="metric"):
    r = requests.get(f"{BASE}/weather", params={"q": city, "appid": API_KEY, "units": units}, timeout=10)
    r.raise_for_status()
    return r.json()

def get_forecast(city, units="metric"):
    r = requests.get(f"{BASE}/forecast", params={"q": city, "appid": API_KEY, "units": units, "cnt": 40}, timeout=10)
    r.raise_for_status()
    return r.json()["list"]

def display_current(d, units):
    sym = "°C" if units == "metric" else "°F"
    print(f"\n{'='*40}")
    print(f"  {d['name']}, {d['sys']['country']}")
    print(f"  {d['weather'][0]['description'].title()}")
    print(f"  Temp: {d['main']['temp']}{sym}  (feels like {d['main']['feels_like']}{sym})")
    print(f"  Humidity: {d['main']['humidity']}%  Wind: {d['wind']['speed']} m/s")
    print("="*40)

def display_forecast(forecast, units):
    sym = "°C" if units == "metric" else "°F"
    print("\n5-Day Forecast:")
    seen = set()
    for entry in forecast:
        dt = datetime.fromtimestamp(entry["dt"])
        if dt.hour == 12 and dt.date() not in seen:
            seen.add(dt.date())
            print(f"  {dt.strftime('%a %b %d')}: {entry['main']['temp']}{sym}  {entry['weather'][0]['description']}")

city = input("City: ").strip()
units = input("Units metric/imperial [metric]: ").strip() or "metric"
try:
    display_current(get_current(city, units), units)
    display_forecast(get_forecast(city, units), units)
except requests.HTTPError as e:
    print(f"Error {e.response.status_code}: city not found or invalid API key")
Bash
export OPENWEATHER_API_KEY=your_key_here
python weather.py
Tip: Store the API key in .env and load with python-dotenv — never commit API keys to git.

🏋️ Practical Exercise

Extend the weather app:

  1. Let the user enter any city name and fetch its current weather.
  2. Display temperature, conditions, and humidity in a readable format.
  3. Handle an invalid city or network error gracefully.
  4. Cache the last result so repeated lookups are instant.

🔥 Challenge Exercise

Build a richer weather tool: show a multi-day forecast, let the user pick Celsius or Fahrenheit, and keep their API key in an environment variable instead of the code. Add robust error handling for bad input, network failures, and rate limits, plus a short retry. Bonus: cache responses for a few minutes and display the data as a small chart.

📋 Summary

  • This project consumes a weather REST API and displays current conditions.
  • The requests library fetches data; the JSON response is parsed for the fields you need.
  • API keys belong in environment variables or config, never hard-coded.
  • Network errors, invalid cities, and rate limits are handled gracefully.
  • Caching avoids redundant calls and speeds up repeated lookups.
  • It can grow with forecasts, unit switching, and charts.

Interview Questions on Building a Weather App

  • How do you call a third-party REST API from Python?
  • How should you store and protect an API key?
  • How do you parse and use a JSON API response?
  • How do you handle network errors and bad responses?
  • Why and how would you cache API results?
  • How do you respect API rate limits?
  • How would you let users switch units or locations?

FAQ

Where should I keep my API key? +

Never hard-code it in the source or commit it to git. Store it in an environment variable (read with os.environ) or a .env file loaded by python-dotenv, and keep that file out of version control.

How do I handle a city that doesn’t exist? +

Check the response status code and body — most weather APIs return an error (e.g. 404) for unknown cities. Detect it and show a friendly message instead of crashing on missing JSON fields.

Why cache the weather data? +

Weather changes slowly and APIs limit how many calls you can make. Caching a result for a few minutes avoids hitting rate limits, reduces latency for repeated lookups, and is gentler on the provider.

What happens if the network request fails? +

Wrap the call in try/except for requests exceptions (timeouts, connection errors), show a clear message, and optionally retry a couple of times with a short delay for transient failures.