Lesson Monday

Now that we've learned about static methods, let's refactor our weather API application to use one. In the process, we'll clean up our code further and separate the logic.

Here's the code so far:


Example GitHub Repo for API Project with Promises

We'll just add one additional file to hold our API logic. We'll call this file weather-service.js and the file will hold a class called WeatherService. Why are we using the term service here? A service is a piece of reusable code that can be shared across an application. In this case, we are separating out our API call so we can make this code available wherever it's needed. In a very large application, we might need to include our service in many different places. That isn't the case here, but using this design pattern will make our application more scalable.

Let's take a look at the code in this file:

src/weather-service.js
export default class WeatherService {  
  static getWeather(city) {
    return new Promise(function(resolve, reject) {
      let request = new XMLHttpRequest();
      const url = `http://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${process.env.API_KEY}`;
      request.onload = function() {
        if (this.status === 200) {
          resolve(request.response);
        } else {
          reject(request.response);
        }
      }
      request.open("GET", url, true);
      request.send();
    });
  }
}

We export a default class because we will only be exporting WeatherService. Next, we use the static keyword to define a static method called getWeather() which takes a city as a parameter.

The code inside this static method is almost exactly the same as it was before. The only difference is that we need to return our promise. There's no need to save the promise in a variable. So this is just a method that returns a promise object. The big gotcha that we see for many students trying to separate out logic is that they forget the return keyword. As we know, functions need to return something or they will be undefined. We've seen many situations where students thought they were getting undefined in their code because they weren't handling asynchrony properly - but the real reason was because a function didn't return anything!

Now let's take a look at the updated code for main.js:

src/main.js
import $ from 'jquery';
import 'bootstrap';
import 'bootstrap/dist/css/bootstrap.min.css';
import './css/styles.css';
import WeatherService from './weather-service.js'

function clearFields() {
  $('#location').val("");
  $('.showErrors').text("");
  $('.showHumidity').text("");
  $('.showTemp').text("");
}

$(document).ready(function() {
  $('#weatherLocation').click(function() {
    let city = $('#location').val();
    clearFields();
    let promise = WeatherService.getWeather(city);
    promise.then(function(response) {
      const body = JSON.parse(response);
      $('.showHumidity').text(`The humidity in ${city} is ${body.main.humidity}%`);
      $('.showTemp').text(`The temperature in Kelvins is ${body.main.temp} degrees.`);
    }, function(error) {
      $('.showErrors').text(`There was an error processing your request: ${error}`);
    });
  });
});

First we need to make sure to import our WeatherService. We make our API call by doing the following:

src/main.js
let promise = WeatherService.getWeather(city);

It should be really clear why our static WeatherService.getWeather() method needs to return a promise - otherwise, the promise variable would be undefined when we use it.

Because the variable holds a promise, we can call Promise.prototype.then() on it:

promise.then(function(response) {
  // Code omitted in snippet.
});

We've also done a little cleanup here by extracting code that clears the DOM into a clearFields() method. If we had a lot of UI methods like this, we might want to extract them into another file as well, but at this point we'll focus on just separating out our business logic - or rather, it would be more accurate to call it our service logic.

In this lesson, we've made some minor changes to our code that make a big difference in terms of separating logic and keep our code concise and clean. You'll be expected to separate code related to API calls into its own file for this section's independent project. If there is any code that alters the DOM in your business logic, it hasn't been separated enough! The WeatherService class we've created here just creates an API call wrapped in a promise. There's no need for any jQuery or DOM alteration.

Here's the project with separated logic:


Example GitHub Repo for API Project with Promises

Lesson 18 of 29
Last updated more than 3 months ago.