Project 2: Weather App
📖 Concept
Build a weather application using the Fetch API and async/await. This project practices API integration, async programming, error handling, and dynamic UI updates.
Features:
- Search by city name or use geolocation
- Display current weather (temperature, humidity, wind, conditions)
- 5-day forecast
- Weather icons and background changes
- Recent searches history
API: OpenWeatherMap free tier (or similar) Concepts practiced: fetch, async/await, try/catch, JSON parsing, Geolocation API, localStorage, template literals
💻 Code Example
1// Weather App — API Integration23class WeatherApp {4 constructor(apiKey) {5 this.apiKey = apiKey;6 this.baseURL = "https://api.openweathermap.org/data/2.5";7 this.recentSearches = JSON.parse(8 localStorage.getItem("recentSearches") || "[]"9 );10 }1112 async getWeather(city) {13 try {14 const response = await fetch(15 `${this.baseURL}/weather?q=${encodeURIComponent(city)}&appid=${this.apiKey}&units=metric`16 );17 if (!response.ok) {18 if (response.status === 404) throw new Error("City not found");19 throw new Error(`HTTP ${response.status}`);20 }21 const data = await response.json();22 this.saveSearch(city);23 return this.formatWeather(data);24 } catch (error) {25 console.error("Weather fetch failed:", error);26 throw error;27 }28 }2930 async getForecast(city) {31 const response = await fetch(32 `${this.baseURL}/forecast?q=${encodeURIComponent(city)}&appid=${this.apiKey}&units=metric`33 );34 if (!response.ok) throw new Error("Forecast unavailable");35 const data = await response.json();36 return this.formatForecast(data);37 }3839 async getByLocation() {40 return new Promise((resolve, reject) => {41 navigator.geolocation.getCurrentPosition(42 async (pos) => {43 const { latitude: lat, longitude: lon } = pos.coords;44 const response = await fetch(45 `${this.baseURL}/weather?lat=${lat}&lon=${lon}&appid=${this.apiKey}&units=metric`46 );47 resolve(this.formatWeather(await response.json()));48 },49 reject,50 { timeout: 10000 }51 );52 });53 }5455 formatWeather(data) {56 return {57 city: data.name,58 country: data.sys.country,59 temp: Math.round(data.main.temp),60 feelsLike: Math.round(data.main.feels_like),61 humidity: data.main.humidity,62 wind: data.wind.speed,63 description: data.weather[0].description,64 icon: data.weather[0].icon,65 iconURL: `https://openweathermap.org/img/wn/${data.weather[0].icon}@2x.png`66 };67 }6869 formatForecast(data) {70 // Group by day, take noon readings71 const daily = data.list72 .filter(item => item.dt_txt.includes("12:00"))73 .slice(0, 5)74 .map(item => ({75 date: new Date(item.dt * 1000).toLocaleDateString("en", {76 weekday: "short"77 }),78 temp: Math.round(item.main.temp),79 icon: item.weather[0].icon,80 description: item.weather[0].description81 }));82 return daily;83 }8485 saveSearch(city) {86 this.recentSearches = [87 city,88 ...this.recentSearches.filter(c => c !== city)89 ].slice(0, 5);90 localStorage.setItem(91 "recentSearches",92 JSON.stringify(this.recentSearches)93 );94 }95}9697// Usage98const app = new WeatherApp("YOUR_API_KEY");99100async function handleSearch(city) {101 const loadingEl = document.querySelector("#loading");102 const errorEl = document.querySelector("#error");103 const weatherEl = document.querySelector("#weather");104105 loadingEl.style.display = "block";106 errorEl.style.display = "none";107108 try {109 const [weather, forecast] = await Promise.all([110 app.getWeather(city),111 app.getForecast(city)112 ]);113 renderWeather(weather);114 renderForecast(forecast);115 } catch (error) {116 errorEl.textContent = error.message;117 errorEl.style.display = "block";118 } finally {119 loadingEl.style.display = "none";120 }121}
🏋️ Practice Exercise
Build It Yourself:
- Get a free API key from OpenWeatherMap
- Build the search UI with autocomplete for city names
- Display current weather with themed backgrounds/icons
- Add 5-day forecast with horizontal scrollable cards
- Implement geolocation-based weather detection
- Save recent searches to localStorage
- Bonus: Add unit toggle (Celsius/Fahrenheit)
⚠️ Common Mistakes
Exposing API keys in client-side code — use environment variables or a proxy server
Not handling the case when geolocation permission is denied
Not URL-encoding the city name — spaces and special characters break the URL
Forgetting to show loading state while fetching — app feels unresponsive
Not debouncing search input — too many API calls on every keystroke
💼 Interview Questions
🎤 Mock Interview
Mock interview is powered by AI for Project 2: Weather App. Login to unlock this feature.