Weather cli app
-
So I've been trying to get better at development and have a deeper understanding of Go. I wrote a small utility to interface with openweathermap.org's API. I had an initial setup that didn't utilize interfaces or methods but I went back and refactored it so that I could add another weather service later if I wanted to. Interfaces allow you to call methods over multiple types. The app just takes two arguments, the city and country where you want the weather.
I'll preface the code with the fact that this is most likely horrible and I'm sure a lot is done incorrectly, so feel free to tear this apart if you actually know what you're doing.
main.go
package main import ( "os" ) type Location struct { City string Country string } type Getter interface { GetWeather() } func Weather(g Getter) { g.GetWeather() } func main() { city := os.Args[1] country := os.Args[2] place := Location{} place.City = city place.Country = country Weather(place) }
openweathermap.go
package main import ( "encoding/json" "fmt" "log" "net/http" "os" ini "gopkg.in/ini.v1" ) type OpenWeather struct { Coord struct { Lon float64 `json:"lon"` Lat float64 `json:"lat"` } `json:"coord"` Weather []struct { ID int `json:"id"` Main string `json:"main"` Description string `json:"description"` Icon string `json:"icon"` } `json:"weather"` Base string `json:"base"` Main struct { Temp float64 `json:"temp"` Pressure int `json:"pressure"` Humidity int `json:"humidity"` TempMin float64 `json:"temp_min"` TempMax float64 `json:"temp_max"` } `json:"main"` Visibility int `json:"visibility"` Wind struct { Speed float64 `json:"speed"` Deg int `json:"deg"` Gust float64 `json:"gust"` } `json:"wind"` Rain struct { OneH float64 `json:"1h"` } `json:"rain"` Snow struct { OneH float64 `json:"1h"` } `json:"snow"` Clouds struct { All int `json:"all"` } `json:"clouds"` Dt int `json:"dt"` Sys struct { Type int `json:"type"` ID int `json:"id"` Message float64 `json:"message"` Country string `json:"country"` Sunrise int `json:"sunrise"` Sunset int `json:"sunset"` } `json:"sys"` ID int `json:"id"` Name string `json:"name"` Cod int `json:"cod"` } func (l Location) GetWeather() { config, err := ini.Load(".weather") if err != nil { fmt.Printf("Failed to load config file %v", err) os.Exit(1) } apiKey := config.Section("").Key("openweather").String() url := fmt.Sprintf("https://api.openweathermap.org/data/2.5/weather?q=%s,%s&units=imperial&appid=%s", l.City, l.Country, apiKey) req, err := http.NewRequest("GET", url, nil) if err != nil { log.Fatal("NewRequest: ", err) } client := http.Client{} resp, err := client.Do(req) if err != nil { log.Fatal("Do: ", err) } defer resp.Body.Close() var weather OpenWeather if err := json.NewDecoder(resp.Body).Decode(&weather); err != nil { log.Println(err) } fmt.Println("Temperature: ", weather.Main.Temp) fmt.Println("Description: ", weather.Weather[0].Description) fmt.Println("Minimum Temperature: ", weather.Main.TempMin) fmt.Println("Maximum Temperature: ", weather.Main.TempMax) fmt.Println("Wind Speed: ", weather.Wind.Speed, " MPH") }
It's looking for an ini file named
.weather
in the same directory as the application. The content should beopenweather = <your_api_key>
I only have a couple parts of the json returned, mostly because I'm lazy. I also have the imperial units hard coded because again, I'm lazy.
-
To build this, you can just create those two files and do a
go build -o weather main.go openweathermap.go
and it will generate your executable.To build it for a different platform (Windows vs Linux) pass the build environment variable in like this:
GOOS=windows go build -o weather.exe main.go openweathermap.go