diff --git a/web/weatherapp/solution/.env.example b/web/weatherapp/solution/.env.example new file mode 100644 index 0000000..6629df7 --- /dev/null +++ b/web/weatherapp/solution/.env.example @@ -0,0 +1,3 @@ +# OpenWeather API Key +# Get your free API key from: https://openweathermap.org/api +WEATHER_API_KEY=your_api_key_here diff --git a/web/weatherapp/solution/.gitignore b/web/weatherapp/solution/.gitignore new file mode 100644 index 0000000..ea05dc2 --- /dev/null +++ b/web/weatherapp/solution/.gitignore @@ -0,0 +1,22 @@ +# Environment variables +.env +.env.local +.env.*.local + +# Dependencies +node_modules/ + +# Logs +logs +*.log +npm-debug.log* + +# OS files +.DS_Store +Thumbs.db + +# IDE +.vscode/ +.idea/ +*.swp +*.swo diff --git a/web/weatherapp/solution/README.md b/web/weatherapp/solution/README.md new file mode 100644 index 0000000..d23aae4 --- /dev/null +++ b/web/weatherapp/solution/README.md @@ -0,0 +1,100 @@ +# ๐ŸŒฆ๏ธ Weather CLI + +A command-line interface tool to fetch real-time weather data from OpenWeather API. + +## โœจ Features + +- ๐ŸŒ Search weather by city name +- ๐ŸŒก๏ธ Display temperature, humidity, wind speed, and more +- ๐Ÿ” Secure API key management using environment variables +- ๐Ÿ›ก๏ธ Comprehensive error handling: + - Invalid city names + - Network connectivity issues + - Invalid API keys + - API errors +- โณ Async/Await based API requests +- ๐Ÿง  Clean ES6+ JavaScript structure + +## ๐Ÿš€ Installation + +1. Clone the repository +2. Install dependencies: + ```bash + npm install + ``` +3. Create a `.env` file based on `.env.example`: + ```bash + cp .env.example .env + ``` +4. Add your OpenWeather API key to `.env`: + ``` + WEATHER_API_KEY=your_actual_api_key + ``` + Get your free API key from: https://openweathermap.org/api + +## ๐Ÿ“– Usage + +Run the CLI tool: +```bash +npm start +``` + +Or: +```bash +npm run dev +``` + +Then enter any city name to get its current weather: +``` +๐ŸŒ Enter city name (or "exit" to quit): London +``` + +## ๐Ÿงช Error Handling + +The CLI handles various error scenarios: + +โœ… **Valid City** +``` +๐ŸŒ Enter city name: London +๐ŸŒฆ๏ธ Weather in London, GB +๐ŸŒก๏ธ Temperature: 15ยฐC +``` + +โŒ **Invalid City** +``` +๐ŸŒ Enter city name: InvalidCity123 +๐ŸŒ City "InvalidCity123" not found. Please check the spelling and try again. +``` + +โš ๏ธ **Network Issues** +``` +๐ŸŒ Network error. Please check your internet connection. +``` + +๐Ÿ” **Invalid API Key** +``` +๐Ÿ” Invalid API key. Please check your WEATHER_API_KEY in .env file. +``` + +## ๐Ÿ—๏ธ Project Structure + +``` +weather-cli/ +โ”œโ”€โ”€ index.js # Main CLI application +โ”œโ”€โ”€ package.json # Project dependencies and scripts +โ”œโ”€โ”€ .env # Environment variables (not committed) +โ”œโ”€โ”€ .env.example # Template for environment variables +โ”œโ”€โ”€ .gitignore # Git ignore rules +โ””โ”€โ”€ README.md # This file +``` + +## ๐Ÿ› ๏ธ Technologies Used + +- Node.js +- OpenWeather API +- ES6+ JavaScript (async/await, destructuring, modules) +- dotenv for environment variable management + +## ๐Ÿ“ License + +ISC diff --git a/web/weatherapp/solution/index.js b/web/weatherapp/solution/index.js new file mode 100644 index 0000000..89f5da1 --- /dev/null +++ b/web/weatherapp/solution/index.js @@ -0,0 +1,107 @@ +import 'dotenv/config'; +import readline from 'readline'; + +const API_KEY = process.env.WEATHER_API_KEY; +const BASE_URL = `http://api.weatherapi.com/v1/current.json?key=${API_KEY}`; + +// Create readline interface for user input +const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout +}); + +/** + * Fetch weather data from WeatherAPI.com + * @param {string} city - City name to search + * @returns {Promise} Weather data + */ +async function fetchWeatherData(city) { + if (!API_KEY) { + throw new Error('โŒ API key not found. Please check your .env file.'); + } + + const url = `${BASE_URL}&q=${encodeURIComponent(city)}`; + + try { + const response = await fetch(url); + const data = await response.json(); + + // Handle API errors (weatherapi.com returns error in response body) + if (data.error) { + if (data.error.code === 1006) { + throw new Error(`๐ŸŒ City "${city}" not found. Please check the spelling and try again.`); + } + if (data.error.code === 2006) { + throw new Error('๐Ÿ” Invalid API key. Please check your WEATHER_API_KEY in .env file.'); + } + throw new Error(`โš ๏ธ API Error: ${data.error.message || 'Unknown error occurred'}`); + } + + if (!response.ok) { + throw new Error(`โš ๏ธ HTTP Error: ${response.status} ${response.statusText}`); + } + + return data; + } catch (error) { + // Handle network errors + if (error.message.includes('fetch')) { + throw new Error('๐ŸŒ Network error. Please check your internet connection.'); + } + throw error; + } +} + +/** + * Display weather information in a formatted way + * @param {Object} data - Weather data from WeatherAPI.com + */ +function displayWeather(data) { + const { location, current } = data; + + console.log('\n' + '='.repeat(50)); + console.log(`๐ŸŒฆ๏ธ Weather in ${location.name}, ${location.country}`); + console.log('='.repeat(50)); + console.log(`๐ŸŒก๏ธ Temperature: ${current.temp_c}ยฐC (feels like ${current.feelslike_c}ยฐC)`); + console.log(`๐Ÿ“Š Condition: ${current.condition.text}`); + console.log(`๐Ÿ’ง Humidity: ${current.humidity}%`); + console.log(`๐Ÿ’จ Wind Speed: ${current.wind_kph} km/h`); + console.log(`๐Ÿ”ฝ Pressure: ${current.pressure_mb} mb`); + console.log('='.repeat(50) + '\n'); +} + +/** + * Prompt user for city and fetch weather + */ +function askForCity() { + rl.question('๐ŸŒ Enter city name (or "exit" to quit): ', async (city) => { + city = city.trim(); + + if (city.toLowerCase() === 'exit' || city.toLowerCase() === 'quit') { + console.log('๐Ÿ‘‹ Thank you for using Weather CLI!'); + rl.close(); + return; + } + + if (!city) { + console.log('โš ๏ธ Please enter a valid city name.'); + askForCity(); + return; + } + + try { + console.log(`\n๐Ÿ” Fetching weather data for "${city}"...`); + const weatherData = await fetchWeatherData(city); + displayWeather(weatherData); + } catch (error) { + console.error(`\n${error.message}\n`); + } + + // Ask for another city + askForCity(); + }); +} + +// Start the CLI +console.log('\n๐ŸŒฆ๏ธ Welcome to Weather CLI'); +console.log('โ”'.repeat(50)); +askForCity(); \ No newline at end of file diff --git a/web/weatherapp/solution/package-lock.json b/web/weatherapp/solution/package-lock.json new file mode 100644 index 0000000..c179102 --- /dev/null +++ b/web/weatherapp/solution/package-lock.json @@ -0,0 +1,28 @@ +{ + "name": "weather-cli", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "weather-cli", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "dotenv": "^17.3.1" + } + }, + "node_modules/dotenv": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.3.1.tgz", + "integrity": "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + } + } +} diff --git a/web/weatherapp/solution/package.json b/web/weatherapp/solution/package.json new file mode 100644 index 0000000..6c787fa --- /dev/null +++ b/web/weatherapp/solution/package.json @@ -0,0 +1,18 @@ +{ + "name": "weather-cli", + "version": "1.0.0", + "description": "A CLI tool to fetch weather data from OpenWeather API", + "main": "index.js", + "scripts": { + "start": "node index.js", + "dev": "node index.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": ["weather", "cli", "openweather", "api"], + "author": "", + "license": "ISC", + "type": "module", + "dependencies": { + "dotenv": "^17.3.1" + } +}