Project: A School Weather Report

Project: A School Weather Report

An API-driven report needs loading, success and failure behavior. This deterministic response teaches data extraction without an API key; the practical request section shows how real fetch connects to an endpoint.

Before this topic, review Project: A Homework List if its terms are unfamiliar.

What you’ll learn

  • Explain project: a school weather report through the school example.
  • Trace the shown operations and distinguish their result from displayed output.
  • Make the practice change and explain its consequence: The validated temperature changes and the success view reflects it.

Work through the school example

This is JavaScript in a browser. Read the initial values, then follow each operation to its displayed result. A declaration names a value, a function call performs an operation, and console.log displays its arguments.

Create this markup in a separate index.html, then place the JavaScript in a script after these elements. Use this isolated practice page so the selectors refer to its markup.

<p id="weather">Loading</p>

JavaScript · browser · complete script for the supplied markup

async function report() {
  try {
    const response = new Response('{"temperature":24}', { status: 200 });
    if (!response.ok) throw new Error("Weather unavailable");
    const data = await response.json();
    if (!Number.isFinite(data.temperature)) throw new Error("Invalid temperature");
    document.querySelector("#weather").textContent = data.temperature + " C";
    console.log(document.querySelector("#weather").textContent);
  } catch (error) {
    document.querySelector("#weather").textContent = error.message;
  }
}
report();

Expected output

24 C

Overview

This project will help you build a Weather App using pure JavaScript and an external API. We will use the OpenWeatherMap API to fetch real-time weather data based on the user's city input.

What You'll Learn

  • How to make HTTP requests using fetch()
  • How to parse and handle JSON data
  • How to build a CLI or console-based tool using JavaScript
  • How to use environment variables to store API keys (Node.js only)

Step 1: Get API Access

Sign up at OpenWeatherMap and get your free API key.

Step 2: Understand the API Request

The API URL to get weather for a city looks like this:

https://api.openweathermap.org/data/2.5/weather?q=London&appid=YOUR_API_KEY&units=metric

Question:

What are the parameters in the API URL?

Answer: q is the city name, appid is your API key, and units=metric ensures temperature is in Celsius.

Step 3: Write JavaScript Code (Browser Console)

This version runs directly in the browser console. Replace YOUR_API_KEY with your actual key.

const city = "Delhi";
const apiKey = "YOUR_API_KEY"; // Replace with your real API key

fetch(`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}&units=metric`)
  .then(response => {
    if (!response.ok) {
      throw new Error("City not found");
    }
    return response.json();
  })
  .then(data => {
    console.log(`Weather in ${data.name}:`);
    console.log(`Temperature: ${data.main.temp}°C`);
    console.log(`Weather: ${data.weather[0].description}`);
    console.log(`Humidity: ${data.main.humidity}%`);
    console.log(`Wind Speed: ${data.wind.speed} m/s`);
  })
  .catch(error => {
    console.error("Error fetching weather data:", error.message);
  });
Weather in Delhi:
Temperature: 32°C
Weather: clear sky
Humidity: 28%
Wind Speed: 3.6 m/s

Code Description

  • fetch() is used to send a GET request to the weather API.
  • We check response.ok to handle invalid cities or errors.
  • data.main.temp, data.weather[0].description etc. extract key weather metrics.
  • Error handling with .catch() ensures graceful failure.

Question:

What happens if the user enters an invalid city name?

Answer: The API returns a 404 status, and our code throws an error with the message "City not found".

Step 4: Run in Node.js (with Readline)

This version lets users enter city names via command line:

// weather.js
const readline = require("readline");
const https = require("https");

const apiKey = "YOUR_API_KEY"; // Replace with your key

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

rl.question("Enter a city name: ", function(city) {
  const url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}&units=metric`;

  https.get(url, (res) => {
    let data = "";
    
    res.on("data", chunk => data += chunk);
    res.on("end", () => {
      const weather = JSON.parse(data);
      if (weather.cod !== 200) {
        console.error("Error:", weather.message);
      } else {
        console.log(`Weather in ${weather.name}:`);
        console.log(`Temperature: ${weather.main.temp}°C`);
        console.log(`Condition: ${weather.weather[0].description}`);
      }
      rl.close();
    });
  }).on("error", (e) => {
    console.error("Failed to fetch:", e.message);
    rl.close();
  });
});
Enter a city name: Paris
Weather in Paris:
Temperature: 21°C
Condition: few clouds

Best Practices

  • Always validate API responses before accessing nested properties.
  • Store API keys securely (e.g., in .env for real-world apps).
  • Handle network errors and empty inputs gracefully.

Wrap-up

This project helped you connect JavaScript to a real-world weather API. You now know how to fetch, parse, and display data dynamically using modern JavaScript techniques.

Recognize the important boundary

The fixed response is not live weather. Real services have units, quotas, credentials and response contracts; do not expose private service keys in browser source.

Try a small variation

JavaScript · original source for practice

async function report() {
  try {
    const response = new Response('{"temperature":24}', { status: 200 });
    if (!response.ok) throw new Error("Weather unavailable");
    const data = await response.json();
    if (!Number.isFinite(data.temperature)) throw new Error("Invalid temperature");
    document.querySelector("#weather").textContent = data.temperature + " C";
    console.log(document.querySelector("#weather").textContent);
  } catch (error) {
    document.querySelector("#weather").textContent = error.message;
  }
}
report();

Your task: Replace "temperature":24 with "temperature":28. Predict the result before running the edited program.

The source is repeated here. If the edit targets the HTML rather than the script, use the markup repeated below; the worked answer also repeats the changed markup.

Markup used by this section:

<p id="weather">Loading</p>

Worked answer and reasoning

The validated temperature changes and the success view reflects it.

Markup for this edited program:

<p id="weather">Loading</p>

JavaScript · complete worked variation

async function report() {
  try {
    const response = new Response('{"temperature":28}', { status: 200 });
    if (!response.ok) throw new Error("Weather unavailable");
    const data = await response.json();
    if (!Number.isFinite(data.temperature)) throw new Error("Invalid temperature");
    document.querySelector("#weather").textContent = data.temperature + " C";
    console.log(document.querySelector("#weather").textContent);
  } catch (error) {
    document.querySelector("#weather").textContent = error.message;
  }
}
report();

Expected output

28 C

Predict the original program

JavaScript · original program for this question

async function report() {
  try {
    const response = new Response('{"temperature":24}', { status: 200 });
    if (!response.ok) throw new Error("Weather unavailable");
    const data = await response.json();
    if (!Number.isFinite(data.temperature)) throw new Error("Invalid temperature");
    document.querySelector("#weather").textContent = data.temperature + " C";
    console.log(document.querySelector("#weather").textContent);
  } catch (error) {
    document.querySelector("#weather").textContent = error.message;
  }
}
report();

Markup used by this section:

<p id="weather">Loading</p>
In the browser, what does the original JavaScript example display, in order?
Choose one answer. You can try again.

Answer and explanation

24 C

An API-driven report needs loading, success and failure behavior. This deterministic response teaches data extraction without an API key; the practical request section shows how real fetch connects to an endpoint. The fixed response is not live weather. Real services have units, quotas, credentials and response contracts; do not expose private service keys in browser source.

Connect the response to a real request

This example makes a real same-origin HTTP request. Provide /__javascript-api/student on your own practice server with JSON such as {"marks":72}. This teaching endpoint is used by the verification server; it is not a public API on the deployed course. A successful response prints 72; HTTP and invalid-data failures enter catch.

For a POST, use fetch(endpoint, {method:"POST", headers:{"Content-Type":"application/json"}, body:JSON.stringify({marks:72})}). The endpoint must implement that contract. Do not retry writes without understanding duplicate processing.

JavaScript · browser · real HTTP request with a practice endpoint

async function loadReport() {
  try {
    const response = await fetch('/__javascript-api/student');
    if (!response.ok) throw new Error('HTTP ' + response.status);
    const student = await response.json();
    if (!Number.isFinite(student.marks)) throw new Error('Invalid mark');
    console.log(student.marks);
  } catch (error) { console.log(error.message); }
}
loadReport();

Expected output

72

Keep the useful idea

An API-driven report needs loading, success and failure behavior. This deterministic response teaches data extraction without an API key; the practical request section shows how real fetch connects to an endpoint.

Check your variation against this explanation: The validated temperature changes and the success view reflects it.

Use the JavaScript array reference library for individual array operations and boundary tests to check a rule independently.

Reaching the recap and completing the quizzes are separate milestones.

    Next lesson: Project: A School Quiz →