Building Weather and Air Quality Check app using LWC and Weatherbit.io api

Use Case:

Sales rep want to see the current weather condition and air quality of particular city or particular pin code


Pre-requisite: 

Signed up a free version from weatherbit.io to get the connection key. 
Create a Named Credential in salesforce org to store the URL which we need to perform the callout.



Implementation:

Apex class:  

Method 1: airQualityCallOut
To get the values of Air Quality from weatherbit api

Method 2: weatherCallOut
To get the values of weather details from weatherbit api

global class WeatherAPIService {
@AuraEnabled (cacheable = true)
global static airQuality airQualityCallOut(String location){
HttpRequest req = new HttpRequest();
req.setEndpoint('callout:WeatherApi/airquality?city=' + location + '&key=222f5227192e4be69aacb6c8deb11337');
req.setMethod('GET');
Http http = new Http();
HTTPResponse res = http.send(req);
JSONParser parser = JSON.createParser(res.getBody());
airQuality airQ = new airQuality();
while (parser.nextToken() != null) {
if(parser.getCurrentToken() == JSONToken.FIELD_NAME) {
parser.nextValue();
switch on parser.getCurrentName() {
when 'aqi' {
airQ.aqi = parser.getText();
}
when 'o3' {
airQ.o3 = Decimal.valueOf(parser.getText());
}
when 'so2' {
airQ.so2 = Decimal.valueOf(parser.getText());
}
when 'no2' {
airQ.no2 = Decimal.valueOf(parser.getText());
}
when 'co' {
airQ.co = Decimal.valueOf(parser.getText());
}
}
}
}
system.debug('airQ'+airQ);
return airQ;
}
@AuraEnabled (cacheable=true)
global static WeatherData weatherCallout(String location,String postalCode) {
HttpRequest req = new HttpRequest();
if (location != ''){
req.setEndpoint('callout:WeatherApi?city=' + location + '&key=222f5227192e4be69aacb6c8deb11337');
}
if (postalCode != ''){
req.setEndpoint('callout:WeatherApi?postal_code=' + postalCode + '&key=222f5227192e4be69aacb6c8deb11337');
}
req.setMethod('GET');
Http http = new Http();
HTTPResponse res = http.send(req);
JSONParser parser = JSON.createParser(res.getBody());
WeatherData weather = new WeatherData();
while (parser.nextToken() != null) {
if(parser.getCurrentToken() == JSONToken.FIELD_NAME) {
parser.nextValue();
system.debug('---->'+parser.getCurrentName() );
switch on parser.getCurrentName() {
when 'temp' {
weather.cityTemp = Decimal.valueOf(parser.getText());
}
when 'city_name' {
weather.cityName = parser.getText();
}
when 'state_code' {
weather.state = parser.getText();
}
when 'timezone' {
weather.cityTimeZone = parser.getText();
}
when 'wind_spd' {
weather.cityWindSpeed = Decimal.valueOf(parser.getText());
}
when 'lon' {
weather.longitude = parser.getText();
}
when 'lat' {
weather.latitude = parser.getText();
}
when 'sunrise' {
weather.sunRise = parser.getText() ;
}
when 'sunset' {
weather.sunSet = parser.getText() ;
}
}
}
}
return weather;
}
global class WeatherData {
@AuraEnabled public String cityName;
@AuraEnabled public String cityTimeZone;
@AuraEnabled public Decimal cityTemp;
@AuraEnabled public String sunRise;
@AuraEnabled public String sunSet;
@AuraEnabled public String state;
@AuraEnabled public Decimal cityWindSpeed;
@AuraEnabled public String latitude;
@AuraEnabled public String longitude;
}
global class airQuality{
@AuraEnabled public String aqi;
@AuraEnabled public Decimal o3;
@AuraEnabled public Decimal so2;
@AuraEnabled public Decimal no2;
@AuraEnabled public Decimal co;
}
}

Lightning web component: weatherForecasting

Here there are two ways to get the weather report based on selected city or based on selected pin code. In html there are two input tags for city and postal code.

Then there are buttons, one is for to check the air quality and another one is for to check the air quality. After clicking the button, just calling the appropriate callout methods using on click event.


weatherForecasting.html

<template>
<lightning-card title={cityName}>
<lightning-layout>
<lightning-layout-item size="3" medium-device-size="4" padding="around-small">

<lightning-input type="text" value={cityValue} label="City Name" onchange={handleChange}>
</lightning-input>

<lightning-input type="text" value={postalValue} label="Postal code" onchange={handleChange}>
</lightning-input>


<lightning-button label="Weather check" onclick={weatherCheck}></lightning-button>
<lightning-button label="Air Quality" onclick={airQualityCheck}></lightning-button>

</lightning-layout-item>
</lightning-layout>

<template if:true={airQualityChk}>
<lightning-layout>

<lightning-layout-item size="5" medium-device-size="4" padding="around-small">
<lightning-card icon-name="standard:topic" title="Air Quality Index">
<div class="slds-align_absolute-center color-blue">
<template if:true={result}>
{aqi}
</template>
</div>
</lightning-card>
</lightning-layout-item>

<lightning-layout-item size="5" medium-device-size="4" padding="around-small">
<lightning-card icon-name="standard:topic" title="O3 Concentration">
<div class="slds-align_absolute-center color-blue">
<template if:true={result}>
{o3}
</template>
</div>
</lightning-card>
</lightning-layout-item>

<lightning-layout-item size="5" medium-device-size="4" padding="around-small">
<lightning-card icon-name="standard:topic" title="SO2 Concentration">
<div class="slds-align_absolute-center color-blue">
<template if:true={result}>
{so2}
</template>
</div>
</lightning-card>
</lightning-layout-item>

<lightning-layout-item size="5" medium-device-size="4" padding="around-small">

<lightning-card icon-name="standard:topic" title="NO2 Concentration">
<div class="slds-align_absolute-center color-blue">
<template if:true={result}>
{no2}
</template>
</div>
</lightning-card>
</lightning-layout-item>

<lightning-layout-item size="5" medium-device-size="4" padding="around-small">

<lightning-card icon-name="standard:topic" title="CO Concentration">
<div class="slds-align_absolute-center color-blue">
<template if:true={result}>
{co}
</template>
</div>
</lightning-card>
</lightning-layout-item>
</lightning-layout>

</template>

<template if:true={weatherchk}>

<lightning-layout>
<lightning-layout-item size="3" medium-device-size="4" padding="around-small">
<lightning-card icon-name="standard:topic" title="Temperature">
<div class="slds-align_absolute-center color-blue">
<template if:true={result}>
{temperature}
</template>
</div>
</lightning-card>
</lightning-layout-item>

<lightning-layout-item size="3" medium-device-size="4" padding="around-small">
<lightning-card icon-name="standard:topic" title="Sun Rise">
<div class="slds-align_absolute-center color-blue">
<template if:true={result}>
<lightning-formatted-time value={sunRise}></lightning-formatted-time>

</template>
</div>
</lightning-card>
</lightning-layout-item>

<lightning-layout-item size="3" medium-device-size="4" padding="around-small">
<lightning-card icon-name="standard:topic" title="Sun set">
<div class="slds-align_absolute-center color-blue">
<template if:true={result}>

<lightning-formatted-time value={sunSet}></lightning-formatted-time>
</template>
</div>
</lightning-card>
</lightning-layout-item>

</lightning-layout>

<lightning-layout>
<lightning-layout-item size="3" medium-device-size="4" padding="around-small">
<lightning-card icon-name="utility:flow" title="Current Wind Speed">
<div class="slds-align_absolute-center color-grey">
<template if:true={result}>
{currentWindSpeed}
</template>
</div>
</lightning-card>
</lightning-layout-item>

<lightning-layout-item size="3" medium-device-size="4" padding="around-small">
<lightning-card icon-name="utility:flow" title="Latitude">
<div class="slds-align_absolute-center color-grey">
<template if:true={result}>
{latitude}
</template>
</div>
</lightning-card>
</lightning-layout-item>

<lightning-layout-item size="3" medium-device-size="4" padding="around-small">
<lightning-card icon-name="utility:flow" title="Longitude">
<div class="slds-align_absolute-center color-grey">
<template if:true={result}>
{longitude}
</template>
</div>
</lightning-card>
</lightning-layout-item>

</lightning-layout>
</template>


<lightning-map map-markers={mapMarkers} zoom-level={zoomLevel}>
</lightning-map>
</lightning-card>
</template>


weatherForecasting.js

import { LightningElement, track } from 'lwc';
import weatherCallout from '@salesforce/apex/WeatherAPIService.weatherCallout';
import airQualityCallOut from '@salesforce/apex/WeatherAPIService.airQualityCallOut';

export default class WeatherDataLWC extends LightningElement {

@track lat;
@track lon;
@track mapMarkers = [];
zoomLevel = 10;
@track result;
cityValue = 'chennai';
postalValue ='';
cityName;
sunSet;
sunRise;
temperature;
currentWindSpeed;
latitude;
longitude;
aqi;
o3;
so2;
no2;
co;
airQualityChk = false;
weatherchk =false;

handleChange(event) {
if (event.target.label === 'City Name'){
this.cityValue = event.target.value;
}
if (event.target.label === 'Postal code'){
this.postalValue = event.target.value;
}
}

/* Method to check the air quality */
airQualityCheck (event){
airQualityCallOut({ location: this.cityValue })
.then(data => {
this.result = data;
if (this.result) {
this.airQualityChk = true;
this.aqi = this.result.aqi ;
this.o3 = this.result.o3;
this.so2 = this.result.so2;
this.no2 = this.result.no2;
this.co = this.result.co;
}
}).catch(err => console.log(err));

}

/* Method to check weather */
weatherCheck(event){
weatherCallout({ location: this.cityValue ,postalCode:this.postalValue })
.then(data => {

//To assign the longitude and latitude to map
this.mapMarkers = [{
location: {
Latitude: data['latitude'],
Longitude: data['longitude']
},
title: data['cityName'] + ', ' + data['state'],
}];
this.result = data;

if (this.result) {
this.weatherchk =true
this.cityName = this.result.cityName + ' Information';
this.sunSet = this.result.sunSet ;
this.sunRise = this.result.sunRise ;
this.temperature = this.result.cityTemp;
this.currentWindSpeed = this.result.cityWindSpeed;
this.latitude = this.result.latitude ;
this.longitude = this.result.longitude;
}
}).catch(err => console.log(err));

}

}



weatherForecasting.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>48.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__AppPage</target>
<target>lightning__HomePage</target>
<target>lightning__Tab</target>
</targets>
</LightningComponentBundle>


GitHub :


Demo: