Weather App Tutorial: Easy Steps to Follow

Weather App Tutorial: Easy Steps to Follow

Introduction🤖

This is a blog on a weather application that covers all of the current data for any area in the world, assisting users in making decisions based on the weather conditions displayed on this app. as it nearly includes major weather aspects such as current weather, current day weather, AQI, humidity, wind speed, dawn and sunset.

In this blog, I'll explain how I made this fantastic application, from design to code.

Technology Used💻

Client: Html, Css, Javascript

Server: Node.js, Express.js

API: Open Weather Api

Figma Design🖌️

I first designed this weather application on Figma, a collaborative web platform for interface design with additional offline features provided by desktop apps. I used this for various reasons, one of which was free.
Below is my Design👇

Step 1: Structure of Project🏖️

The structure of any application is critical because it allows any other person who wants to contribute to the application to easily understand what the app is saying, or any new developer joining their team to learn how things work. While creating an architecture, we make our application more understandable. This allows developers in a company to separate their tasks to work on specific files and contribute to one app.
Check the Structure of the application👇

As you can see from the image above, I believe you understand what this is expressing. If not, carry on to the next line.
There are 3 dots in the image, one is green which refers to the main directory project, another is purple which refers to specific usage folders and the last one is orange which refers to files see below their descriptions.

  • Green is the application project's primary directory (folder), which contains all of the files, subfolders, images, package files, and so on.

    Ex- Weather-App folder in the image

  • Purple one's folders are used for certain functions of the application, and they also contain sub-folders and files within them.

    Ex- Assets, WeatherImg, Client, and Server in the above structure

  • Orange files include a readme, HTML, JS, CSS, images, gitignore, env, and package files.

Step 2: Initiating the Project👍

Follow the steps outlined below:-

  1. Firstly open your git bash terminal, PowerShell or whatever you use and then type the command mkdir Weather-App this will create the folder for your app. If you do not know the commands go to the Cheatsheet📄 that covers all terminal commands.

  2. Now change the directory in your terminal to the weather app by command

    cd Weather-App

  3. Create 3 more folders one for Assets (usually contains the images for the application), another for Client(contains the frontend files that we display too show to users) and last for a server (contains the backend files that users don't see) by typing in the terminal - mkdir Assets Client Server

  4. Again change the directory in the terminal to Weather-App/Assets/ by the command cd Assests it will go to the Assets folder, you can also check if there is anything in that Assets folder by typing a command dir

  5. Now I have another weatherImg folder in Assets so create it the same as above by mkdir weatherImg

  6. Now change the directory to Client and make three files i.e. index.html, style.css and client.js by simply changing the directory to the Client folder and typing the command touch index.html style.css client.js

  7. Now, let's shift to VsCode, which will help us do our tasks faster and easier. will look like the below figure

  8. Open your folder in VsCode and initialize your project to Git(version control system) and Node(javascript framework) by opening a new terminal & then 1'st type command git init after that type npm init for node.js it will add automatically the package.json file & other node_modules

  9. let's install some dependencies required in our application type the command -

    npm install express axios dotenv

  10. Now create a .env and .gitignore file through the GUI in the VsCode

  11. In .env file you have to add the secret key of your weather API which you have to get by simply creating the free account on WeatherAPI & getting the secret key from your profile, see below the example

    Example -

    API_KEY = d8htgh5cb9b66hjy94bba5c5oi542308 // dummy api key
    
  12. .gitignore file is used to not push the secret code and bulky node files to the GitHub, so add the below file name in that file

    # Ignore .env file
    .env
     node_modules/
    
  13. Now everything is ready only the code and some modules are required, so follow the next Backend Part.

Step 3: Backend🔥

Server.js Code - Explanation is given with comments in the code

// server/server.js
const express = require('express'); // import the express framework
const path = require('path'); // import the path module ,provide utilities working with file & directory path
require('dotenv').config(); // import & configure dotenv, loads environment variables from a .env file

const app = express();  //initializes a new express application
const PORT = process.env.PORT || 3000;

// Serve static files from the client directory
app.use(express.static(path.join(__dirname, '../client')));

// Serve static files from the assets directory
app.use('/assets', express.static(path.join(__dirname, '../Assets')));

// API endpoint to fetch weather data
const weatherRouter = require('./weather');
app.use('/weather', weatherRouter);

// Start the server
app.listen(PORT, () => {
    console.log(`Server is running on http://localhost:${PORT}`);
});

Weather.js Code - Explanation is given with comments in the code

// server/weather.js
const express = require('express');
const axios = require('axios');
const router = express.Router();
require('dotenv').config();

const apiKey = process.env.API_KEY;
const apiUrl = 'https://api.weatherapi.com/v1/current.json';

// Modify the route to fetch both current weather and forecast data
router.get('/:location', async (req, res) => {
    try {
        const {location} = req.params;
        // Prepare URLs for both current weather and forecast
        const currentWeatherUrl = `${apiUrl}?key=${apiKey}&q=${location}&aqi=yes`;
        const forecastUrl = `https://api.weatherapi.com/v1/forecast.json?key=${apiKey}&q=${location}&days=3&aqi=yes&alerts=no`; // Adjust 'days' as needed

        // Make both API calls concurrently
        const [currentResponse, forecastResponse] = await Promise.all([
            axios.get(currentWeatherUrl),
            axios.get(forecastUrl)
        ]);

        // Combine both responses into one object
        const combinedData = {
            current: currentResponse.data,
            forecast: forecastResponse.data
        };

        res.json(combinedData);
    } catch (error) {
        console.error('Error fetching weather data:', error);
        res.status(500).json({ error: 'Error fetching weather data' });
    }
});

module.exports = router;

Now let us build the client side part as the frontend code.

Step 4: Frontend❄️

Index.html- Explanation is given with comments in the code

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="style.css">
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link
        href="https://fonts.googleapis.com/css2?family=Kanit:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap"
        rel="stylesheet">
    <title>Weather's Ok</title>
</head>
<body>
    <div class="src-div">
        <input type="text" placeholder="Enter city name" id="inpBar">
        <button class="src-icon"><img src="/Assets/Search-btn.png" alt="Search button"></button>
    </div>
<div>
    <div class="weather-div">
        <div class="div1">
            <div>
                <p class="cityName">New York</p>
                <p class="cityTemp">25°C</p>
            </div>
            <div>
                <p class="cityCond">Thunderstorm</p>
                <p class="date">Monday,28 April</p>
            </div>
        </div>
        <div class="div2">
            <img src="/Assets/WeatherImg/sunny.png" class="weatherImg" alt="weather Images">
        </div>
    </div>
    <div class="hourlyDiv">
        <div class="hour">
            <img src="/Assets/WeatherImg/partly-cloudy.png" alt="">
            <p class="morn" >32°C</p>
            <p id="time1" >07:00 am</p>
        </div>
        <div class="hour">
            <img src="/Assets/WeatherImg/cloudy.png" alt="">
            <p class="even" >32°C</p>
            <p id="time2">06:00 pm</p>
        </div>
        <div class="hour">
            <img src="/Assets/WeatherImg/hail.png" alt="">
            <p class="night" >32°C</p>
            <p id="time3">11:00 pm</p>
        </div>
    </div>
    <div>
        <img class="vecImg" src="/Assets/Vector 4.png" alt="AppDesign">
    </div>
    <div class="weatherMore">
        <div>
            <p>Wind</p>
            <p id="wind">20km/h</p>
        </div>
        <div>
            <p>Air Quality</p>
            <p class="aqi">104 AQI</p>
        </div>
        <div>
            <p>Humidity</p>
            <p class="humid">18%</p>
        </div>
    </div>
    <div class="weatherMore">
        <div>
            <img src="/Assets/WeatherImg/1.png" alt="">
            <p id="rise">Sunrise</p>
            <p class="Rise">05:14 am</p>
        </div>
        <div>
            <img src="/Assets/WeatherImg/4.png" alt="">
            <p id="set">Sunset</p>
            <p class="Set">07:15 am</p>
        </div>
    </div>
</div>    
    <script src="client.js"></script>
</body>
</html>

Style.css - Explanation is given with comments in the code

/*Added few code because of length refer my github repo for code*/
body {
  background-color: #ff9d54;
  margin: 0;
  padding: 0;
  height: 100%;
}
.src-div {
  height: 50px;
  display: flex;
  flex-direction: row;
  margin: 10px 5px 5px 5px;
  justify-content: center;
  gap: 5px;
}
.src-icon {
  background-color: #ffffff;
  border-radius: 50%;
  width: 55px;
  display: flex;
  justify-content: center;
  align-items: center;
  border-color: transparent;
  cursor: pointer;
}
#inpBar {
  width: 100%;
  font-family: Verdana, Geneva, Tahoma, sans-serif;
  font-size: 1rem;
  background: #344A53;
  color: #ff9d54;
  text-align: center;
  text-decoration: none;
  border-radius: 30px;
  border-color: transparent;
}

client.js- Explanation is given with comments in the code

// client/client.js
const searchBtn = document.querySelector('.src-icon')
searchBtn.addEventListener('click', async () => {
//retreives the value from the input element with the ID
  const location = document.getElementById('inpBar').value;
  try {
      const response = await fetch(`/weather/${location}`);
      const weatherData = await response.json();
      console.log(weatherData); // helps to check output in inspect view
      // Call your function to update the DOM with weatherData
      updateWeatherInfo(weatherData);
  } catch (error) {
      console.error('Error fetching weather:', error);
  }
});

function updateWeatherInfo(data) {
  try {
    const current = data.current;
    const forecast = data.forecast;
    const weatherIcon = document.querySelector('.weatherImg');
    document.querySelector('.cityName').innerText = current.location.name;
    document.querySelector('.cityTemp').innerText = `${current.current.temp_c}°C`;
    document.querySelector('.cityCond').innerText = current.current.condition.text;
    document.querySelector('.date').innerText = new Date(current.current.last_updated).toLocaleDateString();
    document.querySelector('.aqi').innerText = `${current.current.air_quality.pm10} AQI`;
    document.querySelector('.humid').innerText = `${current.current.humidity}%`;
    document.getElementById('wind').innerText = `${current.current.wind_kph} km/h`;
    document.querySelector('.Rise').innerText = forecast.forecast.forecastday[0].astro.sunrise;
    document.querySelector('.Set').innerText = forecast.forecast.forecastday[0].astro.sunset;
    document.querySelector('.morn').innerText = `${forecast.forecast.forecastday[0].hour[7].temp_c}°C`;
    document.querySelector('.even').innerText = `${forecast.forecast.forecastday[0].hour[18].temp_c}°C`;
    document.querySelector('.night').innerText = `${forecast.forecast.forecastday[0].hour[23].temp_c}°C`;

    if(current.current.condition.text === 'Sunny'){
      weatherIcon.src = 'Assets/WeatherImg/sunny.png';
    }
    else if(current.current.condition.text === 'Partly cloudy'){
      weatherIcon.src = 'Assets/WeatherImg/partlycloudy.png';
    }
    else if(current.current.condition.text === 'Cloudy'){
      weatherIcon.src = 'Assets/WeatherImg/cloudy.png';
    }
    else if(current.current.condition.text === 'Mist'){
      weatherIcon.src = 'Assets/WeatherImg/drizzle.png';
    }
    else if(current.current.condition.text === 'Patchy rain possible'){
      weatherIcon.src = 'Assets/WeatherImg/showers.png';
    }
    else if(current.current.condition.text === 'Light rain shower'){
      weatherIcon.src = 'Assets/WeatherImg/showers.png';
    }
    else if(current.current.condition.text === 'Fog'){
      weatherIcon.src = 'Assets/WeatherImg/partlycloudy.png';
    }
    else if(current.current.condition.text === 'Light drizzle'){
      weatherIcon.src = 'Assets/WeatherImg/drizzle.png';
    }
    else if(current.current.condition.text === 'Heavy rain'){
      weatherIcon.src = 'Assets/WeatherImg/showers.png';
    }
    else if(current.current.condition.text === 'Partly cloudy'){
      weatherIcon.src = 'Assets/WeatherImg/hail.png';
    }
    else if(current.current.condition.text === 'Heavy snow'){
      weatherIcon.src = 'Assets/WeatherImg/snow.png';
    }
    else if(current.current.condition.text === 'Patchy light rain with thunder'){
      weatherIcon.src = 'Assets/WeatherImg/thunderstorms.png';
    }
    else if(current.current.condition.text === 'Moderate or heavy rain with thunder'){
      weatherIcon.src = 'Assets/WeatherImg/thunderstorms.png';
    }
    else{
      weatherIcon.src = 'Assets/WeatherImg/sunny.png';
    }
  } catch (error) {
    console.error('Error updating weather info:', error);
  }  
}

Step 5: Run the Application🏃‍➡️

To run the application simply go to your terminal and type the command -

node server/server.js and hit enter you will see the link of the localhost after clicking the link you will be redirected to your default browser.

Conclusion
This blog article is a complete tutorial for creating a weather application from scratch, covering the entire development lifecycle from concept to deployment. It describes the technologies utilized, which include HTML, CSS, JavaScript, Node.js, Express.js, and the Open Weather API. The post discusses the project's structure, startup, backend and frontend development, and how to launch the application. The tutorial includes code samples, comments, and explanations to help users create and run effective weather apps.

Follow Me On Socials :

LinkedIn

Twitter

GitHub

Like👍| Share📲| Comment💭

Did you find this article valuable?

Support MOHD NEHAL KHAN by becoming a sponsor. Any amount is appreciated!