Weather web app: web API tutorial

I’m a big fan of web APIs. I made my own, I used them to make online bots; they are fun to play with and can give you inspiration for new projects to work on.

I wrote the original weather web app tutorial about five years ago using Mozilla’s Thimble online code editor. Now that Mozilla is moving Thimble projects to Glitch, I decided to rewrite it. (I’m also a big fan of Glitch.)

How nice.

Let’s begin

This tutorial requires you to have at least a basic understanding of HTML, CSS, and JavaScript. We are going to cover a few concepts:

  • Some basic HTML and CSS
  • JavaScript and AJAX, which is pretty much just HTML, CSS, and JavaScript working together
  • JSON, and JSONP, two formats used for transferring information on the web
  • Signing up for an API key, which you need to be able to make API calls
  • And, of course, making API calls

We will be using Glitch to create and host our web app. Glitch is a really amazing site and a community, and I recommend checking it out outside of this tutorial. Note that you don’t need to sign up for an account to follow along, but your app will be removed after five days.

Let’s start by creating a new web app on Glitch.

Take a moment to read through the README.md file that shows up when you create a new app on Glitch. You can later edit this file to talk about the app you made, but for now let’s keep it as it is.

Let’s go ahead and open index.html in the left sidebar and lay out the structure of our app.

I’d like the page to show the name of the city, the weather, a little information about where we got our data from, and a link to the image we’re using to give credit to its author.

Let’s remove the h1 and p tags and replace them with the following HTML.

<main>
  <h1 id="city"></h1>
  <p id="weather"></p>
</main>
<footer></footer>

We can use the h1 tag for the city name, p tag for weather information, and the footer for credits for our app.

So far so good. But before we can move to the next section, we need to learn a bit more about APIs and API keys.

Keys and secrets

We are going to be using three services in our app:

  • we will use FreeGeoIP.app to get our app’s visitor’s location
  • then we’ll use OpenWeatherMap‘s API to get weather in that location
  • and finally, we’ll search Flickr for images that match the location and weather

Generally speaking, when a website offers an API, they can either let anyone use it without restrictions, or they can enforce certain rules, such as how many API calls you can make per minute, how much data, or what kind of data you can access. To use such restricted APIs you might have to sign up for an account with the API provider, and sometimes also obtain an API key, an API secret, an app ID, an API token, or a combination of these. They all work much like passwords, confirming you are the authorized user of the API. In some case you might also be able to set up a list of domains that are allowed to use the API with your specific API key.

To get an API key from Flickr, visit their App Garden and choose the non-commercial key. After you fill out the application, you should receive your API key (and an API secret, which you won’t need for this tutorial). You can also go to your apps page to get the key later.

Similarly, you will need to sign up for an account at OpenWeatherMap. You can see your API key in your account settings.

And FreeGeoIP.app happens to provide a free tier that doesn’t require an API key.

Now that we have our API keys we can go back to our app in Glitch.

An introduction to XML Http Requests

We are going to make our API calls using the XMLHttpRequest JavaScript object. Feel free to read through the documentation, but let me show you a quick example.

In the Glitch editor, select the script.js file in the left sidebar. You can replace the file’s content with the following JavaScript code:

var xhr = new XMLHttpRequest();

xhr.addEventListener( 'load', function(){
  var response = JSON.parse( xhr.responseText );
  document.getElementById( 'city' ).innerHTML = response.hello;
});

xhr.open( 'GET', 'https://fourtonfish.com/hellosalut/?mode=auto' );
xhr.send();

Let’s go through this code line by line to see what’s happening here. First, we create a new XMLHttpRequest object.

var xhr = new XMLHttpRequest();

We will use this object to send API requests and work with the data that’s sent back to us.

xhr.addEventListener( 'load', function(){
  var response = JSON.parse( xhr.responseText );
  document.getElementById( 'city' ).innerHTML = response.hello;
});

When the data from our API request is loaded, we want to look at the response we received and use it to update the city element on our page.

And when all of this is set up, we open our request and send it on its way.

xhr.open( 'GET', 'https://fourtonfish.com/hellosalut/?mode=auto' );
xhr.send();

It might also help understanding this process if you open the URL I used for the API call directly in your browser.

My server at fourtonfish.com responds to your browser’s request with the following text.

{"code":"en-us","hello":"Hi"}

(The language changes based on your browser’s settings and your location. This is what you’d see if your browser’s language is set to English, or you’re in an English speaking country.)

We can turn this response into a JSON object using JSON.parse and get the value of hello.

The Flickr API works a little bit differently and instead of JSON it works with JSONP (JSON with Padding). The difference between these two formats is that JSONP returns a name of a function in its response and this function will handle the response data in your code.

This will make more sense as we work through the project, no worries.

Let’s put our JavaScript API example code inside a function and call it makeApiCall, so that we can reuse it. We just need to remove the specific URL and pass it as an argument instead. And let’s also add a callback function as an argument. A callback is a function that we want to run after something happens, in our case once our API call gets the data that we want.

Your function should look like this:

function makeApiCall( url, callback ){
  var xhr = new XMLHttpRequest();

  xhr.addEventListener( 'load', function(){
    var response = JSON.parse(xhr.responseText);
    if ( callback ){
      callback( response );
    }
  });

  xhr.open( 'GET', url );
  xhr.send();
}

And now you can use it to make an API call and handle the returned data.

makeApiCall( 'https://fourtonfish.com/hellosalut/?mode=auto', function( data ){
  document.getElementById( 'city' ).innerHTML = data.hello;  
  document.getElementById( 'weather' ).innerHTML = data.code;  
});

Perfect.

Now we can replace the fourtonfish.com URL with https://freegeoip.app/json/.

makeApiCall( 'https://freegeoip.app/json/', function( data ){
  document.getElementById( 'city' ).innerHTML = data.city;  
});

You can click the Show button above the code editor to preview your app.

Quick note here. If you’re using an ad-blocking browser plugin, it might block requests to APIs that detect user’s location. If you run into this, you will either need to disable the plugin on your page, or you can try finding a different service.

Not a bad start.

You can also use console.log( data ) inside your callback function to see what information the returned data object has. (See how to open your browser console.)

- city
- country_code
- country_name
- ip
- latitude
- longitude
- metro_code
- region_code
- region_name
- time_zone
- zip_code

We can use the latitude and longitude information to call the OpenWeatherMap API and ask for weather in that location. (You can find your OpenWeatherMap API key here.)

makeApiCall( 'https://freegeoip.app/json/', function( data ){
  document.getElementById( 'city' ).innerHTML = data.city + ', ' + data.region_name;  

  makeApiCall( 'https://api.openweathermap.org/data/2.5/weather?lat=' + data.latitude + '&lon=' + data.longitude + '&units=imperial&APPID=YOUR_OPENWEATHERMAP_APP_ID', function( data ){
    document.getElementById( 'weather' ).innerHTML = data.weather[0].description;  
  });  
});

Look at that, we are nearly there. Let’s have a look at Flickr now.

As I said before, Flickr’s API uses JSONP, or JSON with Padding. There is a few ways how to handle JSONP responses, here I am going to dynamically add a <script> tag that will load the API as if it was a script file and run the function that handles the data.

function loadBackground( latitude, longitude, weather ) {
  var script_element = document.createElement('script');

  script_element.src = 'https://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=YOUR_FLICKR_API_KEY&lat=' + latitude + '&lon=' + longitude + '&accuracy=1&tags=' + weather + '&sort=relevance&extras=url_l&format=json';

  document.getElementsByTagName('head')[0].appendChild( script_element );
}

If you open the URL we are using for the script tag in your browser, you will see that this script is calling a function called jsonFlickrApi and passes the images to it. So let’s add our jsonFlickrApi function now. (Your Flickr API key can be found here.)

function jsonFlickrApi( data ){
  var photo = data.photos.photo[0];
  document.querySelector( 'body' ).style.backgroundImage = 'url("' + photo.url_l + '")';
}

Again, you can use console.log( data ) for this code to make sense, but all we’re doing is accessing the first photo in the data.photos object that Flickr returned and setting it as a background for our page.

Now let’s add the loadBackground function inside the callback function for our second API call. We should also define variables to store some of the API data so that we can pass it to other functions. Something like this will do the trick.

makeApiCall( 'https://freegeoip.app/json/', function( data ){
  document.getElementById( 'city' ).innerHTML = data.city + ', ' + data.region_name;  
  
  var latitude = data.latitude;
  var longitude = data.longitude;

  makeApiCall( 'https://api.openweathermap.org/data/2.5/weather?lat=' + latitude + '&lon=' + longitude + '&units=imperial&APPID=YOUR_OPENWEATHERMAP_APP_ID', function( data ){
    var weather = data.weather[0].main;
    var weatherDescription = data.weather[0].description;
    document.getElementById( 'weather' ).innerHTML = weatherDescription;

    loadBackground( latitude, longitude, weather );
  });  
});

We just need to add a little bit of CSS to make the background stretch across the whole page without repeating. Also, we can make the text stand out from the background by setting the color to white and giving it a subtle shadow. This will do the trick.

html, body{
  height: 100%;
  overflow: hidden;
}

body{
  background-size: cover;
  background-position: center;
  font-family: sans-serif;
  color: white;
  text-shadow: 1px 1px 10px rgba( 0, 0, 0, 0.4 );  
}

You just made a nice little weather web app, nicely done! You can play around with the styles, make the text larger, see other ways to make it stand out from the background, maybe show more details on the weather, or show a random photo rather than the first one. You could also look into Geolocation API which is supported by many browsers.

I made my own weather web app (source code) if you’d like to see some inspiration. Note that I made my own API that calls the other APIs I used in this tutorial. This way I can keep my API keys private, and add more features later, like caching. (Look out for a follow up tutorial!)

If you get stuck during this tutorial, feel free to reach out either through email or on Twitter, I’ll be happy to help. And be sure to share what you made with me!

Posted 10 months ago in