mirror of
https://github.com/EricNeid/go-openweather.git
synced 2025-01-10 15:05:07 +00:00
Initial commit
This commit is contained in:
commit
084da1a39f
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
*.key
|
||||||
|
debug.test
|
||||||
|
.vscode
|
||||||
|
*.exe
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 Eric Neidhardt
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
5
Makefile
Normal file
5
Makefile
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
build:
|
||||||
|
cd cmd/openweatherclient && go build
|
||||||
|
|
||||||
|
test:
|
||||||
|
go test ./...
|
46
README.md
Normal file
46
README.md
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# go - openweatherapi
|
||||||
|
|
||||||
|
This Repo contains golang library to query OpenWetherMaps (<http://openweathermap.org/>) for weather information.
|
||||||
|
|
||||||
|
* current weather: http://openweathermap.org/current
|
||||||
|
* 5 days forecast: http://openweathermap.org/forecast5
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go get github.com/EricNeid/openweather
|
||||||
|
```
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
Is available on ``godoc``:
|
||||||
|
|
||||||
|
<https://godoc.org/github.com/EricNeid/openweather>
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
Consuming the library:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/EricNeid/openweather"
|
||||||
|
|
||||||
|
// create a query
|
||||||
|
q := openweather.NewQueryForCity(readAPIKey(), "Berlin,de")
|
||||||
|
|
||||||
|
// obtain data
|
||||||
|
resp, err := q.Weather()
|
||||||
|
|
||||||
|
// enjoy
|
||||||
|
fmt.Println(resp.Name) // Berlin
|
||||||
|
fmt.Println(resp.Weather[0].Description) // misc
|
||||||
|
fmt.Println(resp.Main.Temp) // 1
|
||||||
|
```
|
||||||
|
|
||||||
|
See the test files for more example.
|
||||||
|
|
||||||
|
A simple client for testing is also included:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go build cmd/openweatherclient
|
||||||
|
openweatherclient -key <OpenWeather API Key> -city Berlin,de
|
||||||
|
```
|
131
api.go
Normal file
131
api.go
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
// Package openweather contains helper functions to query
|
||||||
|
// OpenWeatherMaps (http://openweathermap.org/) for weather information.
|
||||||
|
// Currently the current weather API (http://openweathermap.org/current) and the
|
||||||
|
// 5 days forecast API (http://openweathermap.org/forecast5) are supported.
|
||||||
|
package openweather
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WeatherRaw downloads current weather data from openweathermap and return them as string.
|
||||||
|
func (query Query) WeatherRaw() (json string, err error) {
|
||||||
|
bytes, err := download(WeatherURL(query))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(bytes), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Weather downloads current weather data from openweathermap and return them as WeatherData.
|
||||||
|
func (query Query) Weather() (*CurrentWeather, error) {
|
||||||
|
bytes, err := download(WeatherURL(query))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dataPtr := &CurrentWeather{}
|
||||||
|
err = json.Unmarshal(bytes, dataPtr)
|
||||||
|
return dataPtr, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DailyForecast5Raw downloads 5 days forecast data from openweathermap and return them as string.
|
||||||
|
func (query Query) DailyForecast5Raw() (json string, err error) {
|
||||||
|
bytes, err := download(DailyForecast5URL(query))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(bytes), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DailyForecast5 downloads 5 days forecast data from openweathermap and return them as DailyForecast5.
|
||||||
|
func (query Query) DailyForecast5() (*DailyForecast5, error) {
|
||||||
|
bytes, err := download(DailyForecast5URL(query))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dataPtr := &DailyForecast5{}
|
||||||
|
err = json.Unmarshal(bytes, dataPtr)
|
||||||
|
return dataPtr, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DailyForecast16Raw downloads 16 days forecast data from openweathermap and return them as string.
|
||||||
|
// Warning: the 16 days forecast requires a paid account.
|
||||||
|
func (query Query) DailyForecast16Raw() (json string, err error) {
|
||||||
|
bytes, err := download(DailyForecast16URL(query))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(bytes), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DailyForecast16 downloads 16 days forecast data from openweathermap and return them as DailyForecast16.
|
||||||
|
// Warning: the 16 days forecast requires a paid account.
|
||||||
|
func (query Query) DailyForecast16() (*DailyForecast16, error) {
|
||||||
|
bytes, err := download(DailyForecast16URL(query))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
dataPtr := &DailyForecast16{}
|
||||||
|
err = json.Unmarshal(bytes, dataPtr)
|
||||||
|
return dataPtr, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func download(url string) (res []byte, err error) {
|
||||||
|
resp, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return body, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WeatherIconURL returns an url to download matching icon for
|
||||||
|
// given weather id.
|
||||||
|
func WeatherIconURL(iconID string) (url string) {
|
||||||
|
return "http://openweathermap.org/img/w/" + iconID + ".png"
|
||||||
|
}
|
||||||
|
|
||||||
|
// DailyForecast5URL returns a matching url for the given query which can be used to obtain the 5 days forecast
|
||||||
|
// from openweathermap.org.
|
||||||
|
func DailyForecast5URL(q Query) string {
|
||||||
|
return "http://api.openweathermap.org/data/2.5/forecast/daily" + formatURLQuery(q)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DailyForecast16URL returns a matching url for the given query which can be used to obtain the 16 days forecast
|
||||||
|
// from openweathermap.org.
|
||||||
|
func DailyForecast16URL(q Query) string {
|
||||||
|
return "http://api.openweathermap.org/data/2.5/forecast/daily" + formatURLQuery(q) + "&cnt=16"
|
||||||
|
}
|
||||||
|
|
||||||
|
// WeatherURL returns a matching url for the given query which can be used to obtain the current weather information
|
||||||
|
// from openweathermap.org.
|
||||||
|
func WeatherURL(q Query) string {
|
||||||
|
return "http://api.openweathermap.org/data/2.5/weather" + formatURLQuery(q)
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatURLQuery(q Query) string {
|
||||||
|
queryType := q.queryType
|
||||||
|
queryValue := q.Query
|
||||||
|
var query string
|
||||||
|
|
||||||
|
if queryType == queryTypeGeo {
|
||||||
|
params := strings.Split(queryValue, "|") // expected format is lat|long
|
||||||
|
lat := params[0]
|
||||||
|
lon := params[1]
|
||||||
|
query = fmt.Sprintf("?lat=%s&lon=%s", lat, lon)
|
||||||
|
} else {
|
||||||
|
query = fmt.Sprintf("?%s=%s", queryType, queryValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
query = query + fmt.Sprintf("&appid=%s&units=%s", q.APIKey, q.Unit)
|
||||||
|
return query
|
||||||
|
}
|
64
api_test.go
Normal file
64
api_test.go
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package openweather
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/EricNeid/openweather/internal/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
const apiKeyFile = "testdata/api.key"
|
||||||
|
const cityBerlin = "Berlin,de"
|
||||||
|
|
||||||
|
func readAPIKey() string {
|
||||||
|
key, err := ioutil.ReadFile(apiKeyFile)
|
||||||
|
if err != nil {
|
||||||
|
panic(`
|
||||||
|
Cannot run test, you must provide openweathermap api key.
|
||||||
|
Expected: testdata/api.key
|
||||||
|
|
||||||
|
See https://home.openweathermap.org/users/sign_up
|
||||||
|
for information how to obtain a key`)
|
||||||
|
}
|
||||||
|
return string(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestForecastRaw(t *testing.T) {
|
||||||
|
// arrange
|
||||||
|
q := NewQueryForCity(readAPIKey(), cityBerlin)
|
||||||
|
// action
|
||||||
|
resp, err := q.DailyForecast5Raw()
|
||||||
|
// verify
|
||||||
|
test.Ok(t, err)
|
||||||
|
test.Assert(t, len(resp) > 0, "Received empty response")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWeatherRaw(t *testing.T) {
|
||||||
|
// arrange
|
||||||
|
q := NewQueryForCity(readAPIKey(), cityBerlin)
|
||||||
|
// action
|
||||||
|
resp, err := q.WeatherRaw()
|
||||||
|
// verify
|
||||||
|
test.Ok(t, err)
|
||||||
|
test.Assert(t, len(resp) > 0, "Received empty response")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWeather(t *testing.T) {
|
||||||
|
// arrange
|
||||||
|
q := NewQueryForCity(readAPIKey(), cityBerlin)
|
||||||
|
// action
|
||||||
|
data, err := q.Weather()
|
||||||
|
// verify
|
||||||
|
test.Ok(t, err)
|
||||||
|
test.Equals(t, "Berlin", data.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDailyForecast(t *testing.T) {
|
||||||
|
// arrange
|
||||||
|
q := NewQueryForCity(readAPIKey(), cityBerlin)
|
||||||
|
// action
|
||||||
|
data, err := q.DailyForecast5()
|
||||||
|
// verify
|
||||||
|
test.Ok(t, err)
|
||||||
|
test.Equals(t, "Berlin", data.City.Name)
|
||||||
|
}
|
29
cmd/openweatherclient/main.go
Normal file
29
cmd/openweatherclient/main.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/EricNeid/openweather"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
keyPtr := flag.String("key", "", "Supply valid api key, see https://home.openweathermap.org/users/sign_up for details.")
|
||||||
|
cityPtr := flag.String("city", "", "City to look up")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if len(*keyPtr) == 0 || len(*cityPtr) == 0 {
|
||||||
|
fmt.Println("Usage: simpleclient.exe -key <api-key> -city <city-to-query>")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
query := openweather.NewQueryForCity(*keyPtr, *cityPtr, "metric")
|
||||||
|
weather, err := query.WeatherRaw()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error while retrieving data: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(weather)
|
||||||
|
}
|
36
internal/test/testing_utils.go
Normal file
36
internal/test/testing_utils.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Assert fails the test if the condition is false.
|
||||||
|
func Assert(t *testing.T, condition bool, msg string, v ...interface{}) {
|
||||||
|
if !condition {
|
||||||
|
_, file, line, _ := runtime.Caller(1)
|
||||||
|
fmt.Printf("\033[31m%s:%d: "+msg+"\033[39m\n\n", append([]interface{}{filepath.Base(file), line}, v...)...)
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ok fails the test if an err is not nil.
|
||||||
|
func Ok(t *testing.T, err error) {
|
||||||
|
if err != nil {
|
||||||
|
_, file, line, _ := runtime.Caller(1)
|
||||||
|
fmt.Printf("\033[31m%s:%d: unexpected error: %s\033[39m\n\n", filepath.Base(file), line, err.Error())
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equals fails the test if exp is not equal to act.
|
||||||
|
func Equals(t *testing.T, exp, act interface{}) {
|
||||||
|
if !reflect.DeepEqual(exp, act) {
|
||||||
|
_, file, line, _ := runtime.Caller(1)
|
||||||
|
fmt.Printf("\033[31m%s:%d:\n\n\texp: %#v\n\n\tgot: %#v\033[39m\n\n", filepath.Base(file), line, exp, act)
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
123
model.go
Normal file
123
model.go
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
package openweather
|
||||||
|
|
||||||
|
// CurrentWeather represents unmarshalled data from openweathermap
|
||||||
|
// for the current weather API (http://openweathermap.org/current).
|
||||||
|
type CurrentWeather 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"`
|
||||||
|
Wind struct {
|
||||||
|
Speed float64 `json:"speed"`
|
||||||
|
Deg int `json:"deg"`
|
||||||
|
} `json:"wind"`
|
||||||
|
Clouds struct {
|
||||||
|
All int `json:"all"`
|
||||||
|
} `json:"clouds"`
|
||||||
|
Rain struct {
|
||||||
|
ThreeH int `json:"3h"`
|
||||||
|
} `json:"rain"`
|
||||||
|
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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DailyForecast5 represents unmarshalled data from openweathermap
|
||||||
|
// for the 5 days forecast weather API (http://openweathermap.org/forecast5).
|
||||||
|
type DailyForecast5 struct {
|
||||||
|
Cod string `json:"cod"`
|
||||||
|
Message float64 `json:"message"`
|
||||||
|
City struct {
|
||||||
|
GeonameID int `json:"geoname_id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Lat float64 `json:"lat"`
|
||||||
|
Lon float64 `json:"lon"`
|
||||||
|
Country string `json:"country"`
|
||||||
|
Iso2 string `json:"iso2"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Population int `json:"population"`
|
||||||
|
} `json:"city"`
|
||||||
|
Cnt int `json:"cnt"`
|
||||||
|
List []struct {
|
||||||
|
Dt int `json:"dt"`
|
||||||
|
Temp struct {
|
||||||
|
Day float64 `json:"day"`
|
||||||
|
Min float64 `json:"min"`
|
||||||
|
Max float64 `json:"max"`
|
||||||
|
Night float64 `json:"night"`
|
||||||
|
Eve float64 `json:"eve"`
|
||||||
|
Morn float64 `json:"morn"`
|
||||||
|
} `json:"temp"`
|
||||||
|
Pressure float64 `json:"pressure"`
|
||||||
|
Humidity int `json:"humidity"`
|
||||||
|
Weather []struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Main string `json:"main"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Icon string `json:"icon"`
|
||||||
|
} `json:"weather"`
|
||||||
|
Speed float64 `json:"speed"`
|
||||||
|
Deg int `json:"deg"`
|
||||||
|
Clouds int `json:"clouds"`
|
||||||
|
Snow float64 `json:"snow,omitempty"`
|
||||||
|
} `json:"list"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DailyForecast16 represents unmarshalled data from openweathermap
|
||||||
|
// for the 16 days forecast weather API (http://openweathermap.org/forecast16).
|
||||||
|
type DailyForecast16 struct {
|
||||||
|
Cod string `json:"cod"`
|
||||||
|
Message float64 `json:"message"`
|
||||||
|
City struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Coord struct {
|
||||||
|
Lon float64 `json:"lon"`
|
||||||
|
Lat float64 `json:"lat"`
|
||||||
|
} `json:"coord"`
|
||||||
|
Country string `json:"country"`
|
||||||
|
} `json:"city"`
|
||||||
|
Cnt int `json:"cnt"`
|
||||||
|
List []struct {
|
||||||
|
Dt int `json:"dt"`
|
||||||
|
Temp struct {
|
||||||
|
Day float64 `json:"day"`
|
||||||
|
Min float64 `json:"min"`
|
||||||
|
Max float64 `json:"max"`
|
||||||
|
Night float64 `json:"night"`
|
||||||
|
Eve float64 `json:"eve"`
|
||||||
|
Morn float64 `json:"morn"`
|
||||||
|
} `json:"temp"`
|
||||||
|
Pressure float64 `json:"pressure"`
|
||||||
|
Humidity int `json:"humidity"`
|
||||||
|
Weather []struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Main string `json:"main"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Icon string `json:"icon"`
|
||||||
|
} `json:"weather"`
|
||||||
|
} `json:"list"`
|
||||||
|
}
|
74
query.go
Normal file
74
query.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package openweather
|
||||||
|
|
||||||
|
// Query represents a pending request to openweathermap.
|
||||||
|
type Query struct {
|
||||||
|
APIKey string
|
||||||
|
Unit string
|
||||||
|
Query string
|
||||||
|
queryType string
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryTypeCity = "q"
|
||||||
|
const queryTypeZip = "zip"
|
||||||
|
const queryTypeID = "id"
|
||||||
|
const queryTypeGeo = "lat|lon"
|
||||||
|
|
||||||
|
// NewQueryForCity creates a query for openweathermap from city name.
|
||||||
|
// The unit is optional and defaults to metric.
|
||||||
|
func NewQueryForCity(apiKey string, city string, unit ...string) Query {
|
||||||
|
u := "metric"
|
||||||
|
if len(unit) > 0 {
|
||||||
|
u = unit[0]
|
||||||
|
}
|
||||||
|
return Query{
|
||||||
|
APIKey: apiKey,
|
||||||
|
Query: city,
|
||||||
|
queryType: queryTypeCity,
|
||||||
|
Unit: u,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewQueryForZip creates a query for openweathermap from zip code.
|
||||||
|
// The unit is optional and defaults to metric.
|
||||||
|
func NewQueryForZip(apiKey string, zip string, unit ...string) Query {
|
||||||
|
u := "metric"
|
||||||
|
if len(unit) > 0 {
|
||||||
|
u = unit[0]
|
||||||
|
}
|
||||||
|
return Query{
|
||||||
|
APIKey: apiKey,
|
||||||
|
Query: zip,
|
||||||
|
queryType: queryTypeZip,
|
||||||
|
Unit: u,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewQueryForID creates a query for openweathermap from city id.
|
||||||
|
// The unit is optional and defaults to metric.
|
||||||
|
func NewQueryForID(apiKey string, id string, unit ...string) Query {
|
||||||
|
u := "metric"
|
||||||
|
if len(unit) > 0 {
|
||||||
|
u = unit[0]
|
||||||
|
}
|
||||||
|
return Query{
|
||||||
|
APIKey: apiKey,
|
||||||
|
Query: id,
|
||||||
|
queryType: queryTypeID,
|
||||||
|
Unit: u,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewQueryForLocation creates a query for openweathermap from latitude and longitude.
|
||||||
|
// The unit is optional and defaults to metric.
|
||||||
|
func NewQueryForLocation(apiKey string, lat string, lon string, unit ...string) Query {
|
||||||
|
u := "metric"
|
||||||
|
if len(unit) > 0 {
|
||||||
|
u = unit[0]
|
||||||
|
}
|
||||||
|
return Query{
|
||||||
|
APIKey: apiKey,
|
||||||
|
Query: lat + "|" + lon,
|
||||||
|
queryType: queryTypeGeo,
|
||||||
|
Unit: u,
|
||||||
|
}
|
||||||
|
}
|
64
query_test.go
Normal file
64
query_test.go
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package openweather
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/EricNeid/openweather/internal/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewQueryForCity(t *testing.T) {
|
||||||
|
// arrange
|
||||||
|
apiKey := "testKey"
|
||||||
|
location := cityBerlin
|
||||||
|
// action
|
||||||
|
q := NewQueryForCity(apiKey, location)
|
||||||
|
// verify
|
||||||
|
test.Equals(t, apiKey, q.APIKey)
|
||||||
|
test.Equals(t, location, q.Query)
|
||||||
|
test.Equals(t, "metric", q.Unit)
|
||||||
|
test.Equals(t, queryTypeCity, q.queryType)
|
||||||
|
|
||||||
|
// arrange
|
||||||
|
unit := "imperial"
|
||||||
|
// action
|
||||||
|
q = NewQueryForCity(apiKey, location, unit)
|
||||||
|
// verify
|
||||||
|
test.Equals(t, unit, q.Unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewQueryForZip(t *testing.T) {
|
||||||
|
// arrange
|
||||||
|
apiKey := "testKey"
|
||||||
|
zip := "12345"
|
||||||
|
// action
|
||||||
|
q := NewQueryForZip(apiKey, zip)
|
||||||
|
// verify
|
||||||
|
test.Equals(t, apiKey, q.APIKey)
|
||||||
|
test.Equals(t, zip, q.Query)
|
||||||
|
test.Equals(t, queryTypeZip, q.queryType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewQueryForID(t *testing.T) {
|
||||||
|
// arrange
|
||||||
|
apiKey := "testKey"
|
||||||
|
id := "42"
|
||||||
|
// action
|
||||||
|
q := NewQueryForID(apiKey, id)
|
||||||
|
// verify
|
||||||
|
test.Equals(t, apiKey, q.APIKey)
|
||||||
|
test.Equals(t, id, q.Query)
|
||||||
|
test.Equals(t, queryTypeID, q.queryType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewQueryForLocation(t *testing.T) {
|
||||||
|
// arrange
|
||||||
|
apiKey := "testKey"
|
||||||
|
lat := "51"
|
||||||
|
lon := "13"
|
||||||
|
// action
|
||||||
|
q := NewQueryForLocation(apiKey, lat, lon)
|
||||||
|
// verify
|
||||||
|
test.Equals(t, apiKey, q.APIKey)
|
||||||
|
test.Equals(t, lat+"|"+lon, q.Query)
|
||||||
|
test.Equals(t, queryTypeGeo, q.queryType)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user