OnlineCBT Logo OnlineCBT
JavaScript Tutorial
JAVASCRIPT · LESSON 36

JS Project: Weather App with Fetch API

By Ratan Updated: 16 Oct 2026

Build a real-time weather forecasting web app using Fetch API and OpenWeather REST endpoint.

Level: Beginner to Advanced
Duration: ~60 Mins Deep-Dive

Fetch current model-based weather for a selected city

This project uses a small city selector so the API work stays focused: build a URL, fetch JSON, validate it, handle cancellation and display units and a timestamp. Open-Meteo's current conditions are model-based data, not a guaranteed live reading from a sensor beside the user.

The public endpoint below is for a learning demo under the provider's applicable non-commercial conditions. Before using it in a monetized/commercial product, check its current terms, licence and commercial endpoint requirements. Keep any private commercial credential on the server.

HTML

City Weather Practice

Choose a city and load its weather.

Weather data: Open-Meteo

weather.js

const cities = {
  jaipur: { name: 'Jaipur', latitude: 26.9124, longitude: 75.7873 },
  delhi: { name: 'Delhi', latitude: 28.6139, longitude: 77.2090 },
  mumbai: { name: 'Mumbai', latitude: 19.0760, longitude: 72.8777 }
};
const form = document.querySelector('#weather-form');
const select = document.querySelector('#city');
const button = document.querySelector('#load');
const status = document.querySelector('#status');
const output = document.querySelector('#weather');
let activeController = null;
let requestNumber = 0;

function addLine(text, tag = 'p') {
  const element = document.createElement(tag);
  element.textContent = text;
  output.append(element);
}
form.addEventListener('submit', async event => {
  event.preventDefault();
  if (!Object.hasOwn(cities, select.value)) {
    status.textContent = 'Choose a listed city.';
    return;
  }
  const city = cities[select.value];
  const number = ++requestNumber;
  activeController?.abort();
  const controller = new AbortController();
  activeController = controller;
  const timer = setTimeout(() => controller.abort(), 12000);
  button.disabled = true;
  output.replaceChildren();
  output.setAttribute('aria-busy', 'true');
  status.textContent = 'Loading weather for ' + city.name + '...';
  try {
    const url = new URL('https://api.open-meteo.com/v1/forecast');
    url.search = new URLSearchParams({
      latitude: String(city.latitude),
      longitude: String(city.longitude),
      current: 'temperature_2m,wind_speed_10m',
      temperature_unit: 'celsius',
      wind_speed_unit: 'kmh',
      timeformat: 'unixtime',
      timezone: 'UTC'
    }).toString();
    const response = await fetch(url, { signal: controller.signal });
    if (!response.ok) throw new Error('Weather service returned HTTP ' + response.status);
    const data = await response.json();
    const current = data.current;
    if (!current || !Number.isFinite(current.temperature_2m)
        || !Number.isFinite(current.wind_speed_10m)
        || !Number.isFinite(current.time)) {
      throw new Error('Weather response is incomplete');
    }
    if (number !== requestNumber) return;
    addLine(city.name, 'h2');
    addLine('Temperature: ' + current.temperature_2m + ' °C');
    addLine('Wind speed: ' + current.wind_speed_10m + ' km/h');
    addLine('Data valid at: ' + new Date(current.time * 1000).toISOString());
    addLine('Source: Open-Meteo model-based current conditions.');
    status.textContent = 'Weather loaded for ' + city.name + '.';
  } catch (error) {
    if (number !== requestNumber) return;
    status.textContent = controller.signal.aborted
      ? 'Request timed out. Please try again.'
      : 'Could not load weather. Check your connection and try again.';
  } finally {
    clearTimeout(timer);
    if (number === requestNumber) {
      button.disabled = false;
      output.setAttribute('aria-busy', 'false');
      activeController = null;
    }
  }
});

Run and inspect

Save the files in a local HTTP-served workspace. Load a city and inspect the request in the Network panel. The response should contain current.temperature_2m, current.wind_speed_10m and a Unix timestamp because timeformat=unixtime was requested. The displayed timestamp is explicitly UTC through toISOString, avoiding an ambiguous location-local time string.

Test checklist

  1. Load each city and verify its label, units and timestamp.
  2. Use offline mode and confirm a readable error with the button re-enabled.
  3. Throttle the connection beyond the timeout and verify recovery.
  4. Test an incomplete/malformed response with a local mock; do not display undefined as weather.
  5. Confirm old requests cannot overwrite a later request result.
  6. Use keyboard-only selection and submission.

Extend carefully

Add city-name search as a separate geocoding step, show several matching places and let the user choose the correct location. Cache briefly and follow rate limits rather than polling continuously. Do not call the data a safety warning system or promise exact current conditions.

Official references: forecast API documentation and usage terms.

📝 Live Lesson Practice

HTML/CSS JavaScript Python C++ C PHP
⌨️ Practice Inputs (लाइव इनपुट भरें) (खाली होने पर RED, भरने पर GREEN underline)
💻 Code Editor (Monaco VS Code Engine)
👀 Live Preview
पता संपर्क करें

+91 7877547686

ई-मेल

onlinecbtportal@gmail.com

हेल्पलाइन नंबर

+91 7877547686


डाउनलोड करने के लिए क्लिक करें
Get it on Google Play

ऐप डाउनलोड करने
के लिए Google Play पर
उपलब्ध है

WhatsApp Chat