Building a weather app with Vite and Node.js

— Thursday, 15 February 2024

Building a weather app is a great way to interact with an external API and the data it returns.

I chose OpenWeatherMap's API as it provides a free plan where you can make up to 60 API calls per minute - more than enough for this project.

Getting an API key

It's free and easy to set up an account. Once you do that you can generate an API key to access their API.

It's common to create and app like this using only front end technologies, fetching data on the client side.

However, even if your API key is stored in a .env file it can still be exposed in browsers' dev tools, should anyone go looking. This could be an expensive mistake should anyone steal your API key and make calls that are charged to your account!

With that in mind, I decided to set up a simple Node.js server that would offer an additional layer of security.

Getting started

After creating the Vite app and removing unrequired boilerplate files, there were a few other packages that I installed on the client side.

i18-iso-countries is a package that takes the country code returned by the API and displays the complete country name. For example, 'FR' would be displayed on the app as 'France'

react-hot-toast is a handy package that can display notifications to the user on the front end, such as errors or messaging to improve user experience.

In the app, if a user tries to fetch weather but forgets to enter a location they would see this:

a web page with a form to enter a location. A notification is showing at the top of the page and says please enter a location

The font end uses a component that contains a form where the user enters the location they want to receive weather information about and a component to display the information returned by the API.

Calling the OpenWeatherMap API

The call to the API begins in the App.jsx file where it receives the location that the user entered in the <Form /> component and when submitted by the user triggers a function to make the API call.

Using the Fetch API a POST request is sent to the node.js server along with the location provided by the user which is converted to JSON and sent in the body of the request object. The node.js server receives the request and the location is interpolated into the API endpoint, along with the API key which is stored in a .env file server-side, which ensures it cannot be viewed should someone nefarious try to find it in the browser's dev tools.

const url = `https://api.openweathermap.org/data/2.5/weather?q=${location}&units=metric&appid=${WEATHER_API_KEY}`

The server responds with status code 200 if the http request was successful and the JSON body response is received in the front end where a setter function updates the state with the weather object received.

A try catch block is used to catch any errors that might occur, such as the API being down or an error in the endpoint.

Unix Timestamp - Epoch time

Sunrise and sunset times are returned from the API as Unix timestamps (Epoch time) and are formatted to Universal Coordinated Time (UTC).

They can be converted to human readable format by using the .toLocaleTimeString() method on a Date instance. Additional options can be added for local customisations.

For example, the sunrise time is returned as 1644916800 and is converted to 07:00 like this:

const sunriseTime = new Date((sunrise + timezone) * 1000).toLocaleTimeString('en-GB', {timeStyle: 'short'})
// 07:00

sunrise is the value returned by the API and timezone is the shift in seconds from Coordinated Universal Time (UCT) in that country. We multiply by 1000 because JavaScript uses milliseconds. It is then converted to human readable form.

Using the time at location to change the background

Once we have the sunrise and sunset times calculated we can obtain the current time at location in a similar way. The currentUTCTime variable uses the getTime() method on the new Date() instance and offsets it if it's British Summer Time using the getTimezoneOffset method.

const utcAtLocation = currentUTCTime + timezone
// UTC at location in seconds
const timeAtLocation = new Date(utcAtLocation * 1000).toLocaleTimeString('en-GB', {timeStyle: 'short'})
// time converted to milliseconds for JS and to human readable form

Knowing the current time at the location allows me to conditionally render a different background for pre or post sunrise, as you can see in the screenshots below:

The weather for Rugby showing 15C overcast clouds time 12.24 and sunrise 7:22 and sunset 17:16 on a blue background which sits on top of a background image of clouds
Day time background image if the time at location is after sunrise and before sunset
The night time weather for Vancouver, Canada wit 4C temperature, overcast clouds, time is 4:24, sunrise 7:22 and sunset 17:31. There is a background image of a starry night with the tops of trees seen at the bottom of the image.
Night time background image if the time at location is after sunset and before sunrise

You can view the weather app deployed here and you can read about how I deployed the app to Render here.

look at the Github repo here

← Back to blogs