Checking the weather is part of billions of people’s daily routine. After all, it influences the clothes we wear, the activities we take part in, how we commute and whether you book that skiing trip that you and your buddies have been talking about for months.
Weather forecasting and reports have come a long way. What used to be something only available on the radio or TV at certain times of day for broad areas can now be precise down to the meter and available to everyone at all times. Technology has allowed weather forecasting to be on-demand, very accurate and accessible. So how can we utilize this for our own projects? Keep reading.
How Can I Get Weather Data for My App?
How exactly will we be getting the weather data for our app? The answer is an API.
In short, an API (short for application programming interface) is something that allows different programs to communicate with each other.
Weather Data APIs
There is a multitude of services that offer weather data through an API. Two of the most common are OpenWeatherMap and Dark Sky. Both have their pros and cons and differences, but for this post, we’ll be using Dark Sky.
If you want to see more weather APIs, check out our list of Top Weather APIs.
Dark Sky API
Dark Sky has a few features that make it powerful and really awesome:
- Minute-by-minute forecasts
- Access to past conditions
- Geographically precise and accurate conditions reports
Dark Sky gathers weather data from sources all around the world and then aggregates them, making them easily available to us all in one place in a predictable format.
About the API
The Dark Sky API is a JSON API. This means that it will respond to our requests with data in JSON format. JSON stands for JavaScript Object Notation. This means that parsing the response we get from Dark Sky will be very easy.
The Dark Sky API works on a freemium model. Your first x amount of requests are free, then every request after that incurs an extra charge (currently $0.001 US).
Building our Weather App
We’re going to be making a simple web application that will allow us to see the weather and forecast for our current location. For this, we’ll be using Node.js and Express for our backend and HTML with some JavaScript for our frontend. For our actual weather data, we’ll be using Dark Sky.
Getting Ready – Backend
As previously said, we’ll be using NodeJS and Express for our backend. Express is a framework that allows us to easily build web servers in NodeJS.
Let’s get started by initializing our project. Open Command Prompt (Windows), Terminal (macOS) or any other command line you use. Move to the directory you want to work in and run the following:
npm init
You’ll be asked a few questions about your project. If you don’t feel like answering them, just press enter and it will use the default. NPM stands for Node Package Manager. The npm
CLI is how we interact with the NPM Registry. The registry is where people put useful modules that they’ve created so that others can use them. For this project, we need the express and unirest packages. To add these to our project, run npm install express unirest
–save. Cool! Now that we have all the packages we need we can get started.
Backend Server
Let’s get started with our Express server. Create a file called Server.js in your working directory and open it in your editor of choice. Our first two lines will be requiring the two modules we added earlier. The require function tells Node to load a module or file into memory and store it as the variable we name on the left side of the equals sign.
Now, this is a start, but our server doesn’t actually do anything yet. The first thing we need to do is set up our Express server. To do this, add the following line after the two require statements.
const app = express();
This will create a constant called app. This is our instance of Express. To make our Express server actually listen on the network for requests we need to tell it to do so. We do this by calling the listen function. Place the code below at the bottom of Server.js and create some new lines between it and the line we just added.
app.listen(3000, () => { console.info('Listening on port :3000'); });
Now our server can listen. Go ahead and run it by running node Server.js
in your command shell. Assuming nothing else is running on port 3000 on your machine, you should get the line “Listening on port :3000” printed to your console. Now navigate to http://localhost:3000 in your browser. You should see something like Cannot GET /
. This is because we haven’t actually added any routes. Routes are how we tell Express to handle requests. We’ll create a route for / here to demonstrate how routes work. Add the following code between initializing Express and the app.listen.
app.get('/', (req, res) => { res.send('Hello world!'); });
Now, restart your app (Control + C, then run node Server.js again). Now, try to navigate to http://localhost:3000 in your browser again. You should see “Hello world!”. Now we’re actually going to delete this route because we’re going to be doing something different with our home page. Under const app = express();
, add app.use(express.static('/public'));
and create a folder called public in our app’s directory. This will make Express try to serve the files in our public folder. This is where we’re going to be putting our HTML.
Getting Your Dark Sky API Credentials
In order to use the Dark Sky API, we have to get API credentials. To do this, go to the RapidAPI page for Dark Sky and subscribe to it. Scroll down to the Header Parameters section and copy the values for X-Rapid-API-Host
and X-RapidAPI-Key
into a new file called apiCredentials.json
in your app’s directory. Your JSON file should look like this:
{ "host": "<X-Rapid-API-Host>", "apiKey": "<X-Rapid-API-Key>" }
It goes without saying, but replace <X-Rapid-API-Host>
and <X-Rapid-API-Key>
with the values you copied from the RapidAPI Dark Sky page. Now add the following line under our two require statements in Server.js.
const credentials = require('./apiCredentials.json');
We’ll use this later.
Experimenting with the Dark Sky API
Now that you’re subscribed to the Dark Sky API, take some time to experiment with it. We’ll look at the GET Forecast endpoint for now, as it’s the main endpoint that we’ll be using. On the RapidAPI Dark Sky page, fill in any latitude and longitude values you want under the Required Parameters section, and then click Test Endpoint. If you scroll down in the Test Result section, you can see the JSON data we got back from Dark Sky under the Response Body section. If you look inside the currently object, you’ll see the current conditions for the location. In the next section, we’ll get into using the Dark Sky API within our app.
Integrating the Dark Sky API With Our Server
Now that we’ve played with the Dark Sky API a bit and have our Express server set up, it’s time to integrate the two. Create a new GET
route in Server.js for the path /weather
. It should look something like this:
app.get('/weather', (req, res) => { });
The req
and res
parameters that are being passed to our function stand for request and response respectively. If you want to learn more about Express, check out the Express Documentation. Inside of req
is what the client making the request sends, this is where we’ll get the user’s location from. res
is how we respond to the client. We’re going to have the client send their latitude and longitude coordinates as query parameters. Query parameters, simply put, are the things after the & in URLs. We’re going to need to get the latitude and longitude values from the query parameters, so add this line to the beginning of the weather route function:
const { lat, lon } = req.query;
This will create two variables, called lat
and lon
. They will contain the values of the lat
and lon
parameters in the URL. Now, let’s use these values to get the weather for the location of our user.
Making Requests to Dark Sky From Node
To make requests to Dark Sky we’re going to use unirest, an NPM module for making HTTP requests. We’ll use unirest to get the current conditions.
const { lat, lon } = req.query; let request = unirest("GET", `https://${credentials.host}/${lat},${lon}`); request.query({ lang: "en", units: "auto" }); request.headers({ "x-rapidapi-host": credentials.host, "x-rapidapi-key": credentials.apiKey }); request.end(response => { if (response.error) res.status(500).end(); // Send an error code to the client if there's an error const { summary, precipProbability, temperature, windSpeed, windBearing } = response.body.currently; // Pull out everything we need from the response res.status(200).send( JSON.stringify({ summary: summary, chanceOfRain: precipProbability, temp: temperature, wind: { speed: windSpeed, bearing: windBearing } }) ); });
This might look like a lot, but it’s pretty simple when broken down. Let’s good at each component.
The first line creates a variable called request
, which is an instance of a unirest request, then we pass it two parameters: request type (“GET”) and the URL to make the request to. This URL might look confusing, but it’s just a JavaScript template literal. Whatever is inside of the brackets of each ${}
is evaluated and then added to the string, so `https://${credentials.host}/${lat},${lon}`
will evaluate to 'https://dark-sky.p.rapidapi.com/37.769421,-122.486214'
(In case you’re wondering, those coordinates are for beautiful Golden Gate Park in San Francisco).
Next, request.query
adds to query parameters to our request: lang
(language) and units
. “en” is short for English and “auto” will let Dark Sky determine the best units to use.
request.headers
is similar to request.query
, but instead of query params it adds headers to our request. The headers we add are our API credentials for Dark Sky.
The next section is the most complicated one, so we’ll break this part down into pieces as well. We pass request.end
a function. request.end
sends a request and then runs the function we pass to it and supplies it the data is got back. Our function has one parameter: response
. This will contain the response from Dark Sky.
The first line of the function checks if the request errored, and if it did it will respond to our client and tell them that an error was encountered (500
is the error code Internal Server Error
).
Here is where we handle the response we got:
const { summary, precipProbability, temperature, windSpeed, windBearing } = response.body.currently;
The left side of the equals sign is declaring variables. Each thing inside the {}
‘s is a variable that is being declined using destructuring. If you’re confused by the variables being inside brackets, you can check out this explanation of what destructuring is. All you need to know is that each variable inside the brackets will have the value of the property by the same name inside response.body.currently
.
Then, we send the data to our client. res.status
sets the status code of the response (200 is the response code for success). Then we send it a stringified JSON object containing all the weather data it will need using res.send
.
Great, we’re done with the server-side of our app!
Making Our Client
With the server all set up, all that’s left to do is set up a web page to act as a client. Our client will make HTTP requests to our server to get weather data.
Writing the HTML
Webpages are written in HTML. HTML stands for Hypertext Markup Language. Create a file inside your public
directory called index.html
and paste this code into it:
<html> <head> <title>My Weather App</title> <script type="text/javascript"> function getLocation() { console.log("getting location"); if (navigator.geolocation) { // navigator is a tool provided by browsers that allows JavaScript to request and get a user's location, this line checks if the browser supports navigator functionality navigator.geolocation.getCurrentPosition(getWeather, weatherError, { timeout: 10000 }); // get the user's geolocation and then pass it to the getWeather function, if it errors, we'll handle the error with the weatherError function } else { document.getElementById("weather").innerHTML = "<h1>Your browser does not support geolocation!<h2>"; // inform the user that their browser does not support geolocation } } function getWeather(position) { var coords = position.coords; console.log(coords); var request = new XMLHttpRequest(); request.addEventListener("load", onloadhandler); // once the response loads, handle it with our onloadhandler function function onloadhandler() { console.log('loading') var { summary, chanceOfRain, temp, wind } = JSON.parse( this.responseText ); // again, use destructuring to pull out the values we need document.getElementById( "weather" ).innerHTML = `<h1>The Weather Is ${summary} (${temp}ºF)</h1> <p>Chance of rain: ${chanceOfRain}%</p><strong>Wind</strong><p>Speed: ${wind.speed} ${wind.bearing}</p>`; // get the element called weather and set its HTML content to this string with the values from our request }; request.open( "GET", `https://localhost:3000/weather?lat=${position.coords.latitude}&lon=${position.coords.longitude}` ); request.send(); } function weatherError(error) { console.error(error); // log the error to the console } </script> </head> <body onload="getLocation()"> <!-- when our page loads, run the javascript --> <div id="weather"> Loading the weather <!-- placeholder until our data loads --> </div> </body> </html>
I’ve included comments to explain what each part does.
Finishing Up
Awesome! Now you can run your app, and navigate to localhost:3000
and you should see your page, then it should show you the weather for your location! Thanks for reading!
YongAi Low says
Hi, everythings seems to work fine until I needed to open the server. Although on my console it says connected to port 3000, the browser console says 2localhost/:1 Failed to load resource: the server responded with a status of 404 (Not Found). I tried using both Chrome and Safari and they both do not work. Any idea how to solve this issue? I am quite new to backend coding.
Shoaib Mehmood says
Hi. That may be bcz you have not started the server. You can run the server by typing in the directory of your folder “node server.js” or whatever your file name is.