How to Use Golang to Check the Weather
In this post, we'll walk through how to build a CLI app using Golang that retrieves and displays the weather for a given location using the weatherapi.com API.
Step 1: Import Required Packages
First, we need to import the packages we'll need to interact with the API and process the data. We need to import encoding/json
for JSON decoding, fmt
for output, io
for IO functions, net/http
for HTTP requests, os
for command-line arguments, and time
for date and time handling. We'll also use the github.com/fatih/color
package to add some color to our output.
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"time"
"github.com/fatih/color"
)
Step 2: Define Weather Struct
Next, we'll define a struct to hold the weather data retrieved from the API. We'll tag each field with their coresponding JSON property.
type Weather struct {
Location struct {
Name string `json:"name"`
Country string `json:"country"`
} `json:"location"`
Current struct {
TempC float64 `json:"temp_c"`
Condition struct {
Text string `json:"text"`
} `json:"condition"`
} `json:"current"`
Forecast struct {
Forecastday []struct {
Hour []struct {
TimeEpoch int64 `json:"time_epoch"`
TempC float64 `json:"temp_c"`
Condition struct {
Text string `json:"text"`
} `json:"condition"`
ChanceOfRain float64 `json:"chance_of_rain"`
} `json:"hour"`
} `json:"forecastday"`
} `json:"forecast"`
}
Step 3: Define Main Function
Now, we'll define the main function of our program. We'll start by setting a default location ("Iasi") in case no command-line arguments are provided. Then, we'll make an HTTP request to the weatherapi.com API to retrieve the weather data for the specified location. We'll then decode the JSON response and store it in our "weather" struct.
func main() {
q := "Iasi"
if len(os.Args) >= 2 {
q = os.Args[1]
}
res, err := http.Get("http://api.weatherapi.com/v1/forecast.json?key=getYourOwnKey&q=" + q + "&days=1&aqi=no&alerts=no")
if err != nil {
panic(err)
}
defer res.Body.Close()
if res.StatusCode != 200 {
panic("Weather API not available")
}
body, err := io.ReadAll(res.Body)
if err != nil {
panic(err)
}
var weather Weather
err = json.Unmarshal(body, &weather)
if err != nil {
panic(err)
}
}
Step 4: Output Weather Data
With the weather data stored in our "weather" struct, we can now output it to the user. We'll start by extracting the relevant data and then output the current weather conditions.
location, current, hours := weather.Location, weather.Current, weather.Forecast.Forecastday[0].Hour
fmt.Printf("%s, %s: %.0fC, %s\n", location.Name, location.Country, current.TempC, current.Condition.Text)
Then we loop through the hours slice and print the forecast to the console. We use the time.Unix()
function to convert the time epoch returned by the API to a date we can compare with the current time (time.Now()
) such that we skip hours that are in the past. If the chances of rain are more than 40%, we print the output in red.
for _, hour := range hours {
date := time.Unix(hour.TimeEpoch, 0)
if date.Before(time.Now()) {
continue
}
message := fmt.Sprintf("%s - %.0fC, %.0f%%, %s\n", date.Format("15:04"), hour.TempC, hour.ChanceOfRain, hour.Condition.Text)
if hour.ChanceOfRain < 40 {
fmt.Print(message)
} else {
color.Red(message)
}
}
And that's it! We have created a simple Go program that retrieves and displays the weather forecast for the next few hours using the Weather API.
Final program:
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"time"
"github.com/fatih/color"
)
type Weather struct {
Location struct {
Name string `json:"name"`
Country string `json:"country"`
} `json:"location"`
Current struct {
TempC float64 `json:"temp_c"`
Condition struct {
Text string `json:"text"`
} `json:"condition"`
} `json:"current"`
Forecast struct {
Forecastday []struct {
Hour []struct {
TimeEpoch int64 `json:"time_epoch"`
TempC float64 `json:"temp_c"`
Condition struct {
Text string `json:"text"`
} `json:"condition"`
ChanceOfRain float64 `json:"chance_of_rain"`
} `json:"hour"`
} `json:"forecastday"`
} `json:"forecast"`
}
func main() {
q := "Iasi"
if len(os.Args) >= 2 {
q = os.Args[1]
}
res, err := http.Get("http://api.weatherapi.com/v1/forecast.json?key=ec180872243c4f57a4f153631230105&q=" + q + "&days=1&aqi=no&alerts=no")
if err != nil {
panic(err)
}
defer res.Body.Close()
if res.StatusCode != 200 {
panic("Weather API not available")
}
body, err := io.ReadAll(res.Body)
if err != nil {
panic(err)
}
var weather Weather
err = json.Unmarshal(body, &weather)
if err != nil {
panic(err)
}
location, current, hours := weather.Location, weather.Current, weather.Forecast.Forecastday[0].Hour
fmt.Printf(
"%s, %s: %.0fC, %s\n",
location.Name,
location.Country,
current.TempC,
current.Condition.Text,
)
for _, hour := range hours {
date := time.Unix(hour.TimeEpoch, 0)
if date.Before(time.Now()) {
continue
}
message := fmt.Sprintf(
"%s - %.0fC, %.0f%%, %s\n",
date.Format("15:04"),
hour.TempC,
hour.ChanceOfRain,
hour.Condition.Text,
)
if hour.ChanceOfRain < 40 {
fmt.Print(message)
} else {
color.Red(message)
}
}
}