Demo Application

Learn how to integrate the AccuWeather APIs in a simple React weather application coupled with an Express server.

In this lesson, we'll see a simple weather application built using Bootstrap and AccuWeather APIs with the JavaScript-based frontend library, React. We'll also create a backend server using Express.js to make API calls to the AccuWeather API server. This application will provide us with current weather information and daily index data for different indices for locations of our choice. Moreover, it will provide hourly forecasts for a period of 12 hours and daily weather forecasts for a period of 5 days for the given location.

Workflow

Step 1: Click the "Run" button to start the application. The output screen is split into two halves. The left half shows the output from our backend server. The right half shows the console log for our frontend application.

Step 2: Click the URL next to "Your app can be found at:" in the widget below to open the application in a new tab.

Step 3: Once the application is ready, we see a homepage with a search bar. Enter a location of your choice.

Step 4: After entering the location in the search bar, press "Enter" or click the search icon.

Step 5: We now see the search bar displayed to the left of the screen and current weather information displayed to the right. We also see three tabs, one each for "Hourly Forecasts," "Daily Forecasts," and "Daily Indices." Switch between tabs to check out the corresponding weather data.

Step 6 (optional): Change the location in the search bar to get weather data for a different location.

Application code

import fetch from "node-fetch";
import express from "express";

const app = express();
const API_KEY = "{{API_KEY}}";

app.use(function (req, res, next) {
  res.setHeader("Access-Control-Allow-Origin", "*");
  res.setHeader("Access-Control-Allow-Headers","Origin, X-Requested-With, Content-Type, Accept, Authorization");
  res.setHeader("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS");
  next();
});

const port = process.env.PORT || 4000;

async function sendLocationsResponse(response, statusCode, res) {
  try {
    const content = await response.json();

    var finalResponse = {
      'Type': 'LocationsData',
      'Status': statusCode,
      'Locations': content
    }

    res.end(JSON.stringify(finalResponse));
    
  } catch (err) {
    console.log(`Error: ${err}`);
  }
}

async function sendForecastResponse(responseDaily5Day, responseHourly12Hour, responseCurrentConditions, responseDaily1Indices, statusCode, res) {
  try {
    const contentDaily5Day = await responseDaily5Day.json();
    const contentHourly12Hour = await responseHourly12Hour.json();
    const contentCurrentConditions = await responseCurrentConditions.json();
    const contentDaily1Indices = await responseDaily1Indices.json();
    
    var finalResponse = {
      'Type': 'WeatherData',
      'Status': statusCode,
      'Daily5Day': contentDaily5Day,
      'Hourly12Hour': contentHourly12Hour,
      'CurrentConditions': contentCurrentConditions,
      'Daily1Indices': contentDaily1Indices
    }

    res.end(JSON.stringify(finalResponse));

  } catch (err) {
    console.log(`Error: ${err}`);
  }
}

// Function to make API call
async function getLocations(url, queryParameters, options, res) {
  try {
    url.search = queryParameters;
    const response = await fetch(url, options);
    // Custom function for printing the API response
    sendLocationsResponse(response, response.status, res);
  } catch (error) {
    console.log(`Error: ${err}`);
  }
}

// Function to make API call
async function getForecasts(urlDaily5Day, urlHourly12Hour, urlCurrentConditions, urlDaily1Indices, queryParameters, options, res) {
  try {
    urlDaily5Day.search = queryParameters;
    urlHourly12Hour.search = queryParameters;
    urlCurrentConditions.search = queryParameters;
    urlDaily1Indices.search = queryParameters;

    const responseDaily5Day = await fetch(urlDaily5Day, options);
    const responseHourly12Hour = await fetch(urlHourly12Hour, options);
    const responseCurrentConditions = await fetch(urlCurrentConditions, options);
    const responseDaily1Indices = await fetch(urlDaily1Indices, options);

    var statusCode = 503;
    if (responseDaily5Day.status === 200 && responseHourly12Hour.status === 200 && responseCurrentConditions.status === 200 && responseDaily1Indices.status === 200)
      statusCode = 200;
    else if (responseDaily5Day.status === 401 && responseHourly12Hour.status === 401 && responseCurrentConditions.status === 401 && responseDaily1Indices.status === 401)
      statusCode = 401;

    // Custom function for printing the API response
    sendForecastResponse(responseDaily5Day, responseHourly12Hour, responseCurrentConditions, responseDaily1Indices, statusCode, res);
  } catch (error) {
    console.log(`Error: ${err}`);
  }
}

app.get("/getLocationsData", function (req, res) {
  const location = req.query.location;

  const url = new URL(`http://dataservice.accuweather.com/locations/v1/cities/autocomplete`);

  // Define header parameters here
  const headerParameters = {
    contentType: "application/json",
  };

  // Define query parameters here
  const queryParameters = new URLSearchParams({
    apikey: API_KEY,
    q: location
  });

  // Setting API call options
  const options = {
    method: "GET",
    headers: headerParameters,
  };

  // Calling function to make API call
  getLocations(url, queryParameters, options, res);
});

app.get("/getWeatherData", function (req, res) {
  const locationKey = req.query.locationKey;

  const urlDaily5Day = new URL(`http://dataservice.accuweather.com/forecasts/v1/daily/5day/${locationKey}`);
  const urlHourly12Hour = new URL(`http://dataservice.accuweather.com/forecasts/v1/hourly/12hour/${locationKey}`);
  const urlCurrentConditions = new URL(`http://dataservice.accuweather.com/currentconditions/v1/${locationKey}`);
  const urlDaily1Indices = new URL(`http://dataservice.accuweather.com/indices/v1/daily/1day/${locationKey}`);

  // Define header parameters here
  const headerParameters = {
    contentType: "application/json",
  };

  // Define query parameters here
  const queryParameters = new URLSearchParams({
    apikey: API_KEY,
    details: true
  });

  // Setting API call options
  const options = {
    method: "GET",
    headers: headerParameters,
  };

  // Calling function to make API call
  getForecasts(urlDaily5Day, urlHourly12Hour, urlCurrentConditions, urlDaily1Indices, queryParameters, options, res);
});

app.listen(port);
console.log("Server started at {{EDUCATIVE_LIVE_VM_URL}}:" + port);
The weather application

Code explanation

Now, let's dive into the application code to get an overview of how we've integrated the AccuWeather APIs into our application.

As we can see, our application comprises a backend server and a frontend web application. Let's discuss each module one by one:

  • The accuweather/backend/server.js file is our backend server developed in Express.js.

    • Lines 94–118: We define a custom route for a call to the /getLocationsData endpoint from our frontend application. This endpoint will make a single API call to the AccuWeather API server using the getLocations() function given on lines 57–66 to retrieve a list of all locations matching the given text.

    • Lines 120–147: We define a custom route for a call to the /getWeatherData endpoint from our frontend application. This endpoint will make four API calls to the AccuWeather API server using the getForecasts() function given on lines 69–92. This will provide the current weather information and daily index data for different indices, along with hourly and daily forecasts for a period of 12 hours and 5 days, respectively.

  • The accuweather/frontend/src/Components folder contains the different components of our frontend React application. Let's discuss them one by one:

    • The CurrentWeather component displays the current weather data.

    • The DailyIndices component displays the daily index values for all indices.

    • The DailyForecasts component displays the weather forecasts for the next 5 days.

    • The Form component displays the input data form.

    • The HourlyForecasts component displays the weather forecasts for the next 12 hours.

    • The Home component provides an interface for the user to search weather data for various locations, which is then displayed using the above-mentioned components. In case the location is not found, or the API call fails, an appropriate message is displayed.

  • The useFetch hook, accuweather/frontend/src/Hooks/useFetch.jsx, makes API calls to our backend server for weather and location data. It then passes the response from the backend server to the Home component to display.