Skip to content

Commit 51f3c6b

Browse files
committed
Added weather forecast
1 parent 7d6d4fd commit 51f3c6b

File tree

4 files changed

+169
-11
lines changed

4 files changed

+169
-11
lines changed

pkg/weatherapi/client.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,31 @@ func (c *Client) Current(q string) (Weather, error) {
7373
return response, nil
7474
}
7575
}
76+
77+
// Forecast weather
78+
func (c *Client) Forecast(q string, opts ...Opt) (Forecast, error) {
79+
var request options
80+
var response Forecast
81+
82+
// Set defaults
83+
request.Values = url.Values{}
84+
response.Query = q
85+
86+
// Set options
87+
for _, opt := range opts {
88+
if err := opt(&request); err != nil {
89+
return Forecast{}, err
90+
}
91+
}
92+
93+
// Set query parameters
94+
request.Set("key", c.key)
95+
request.Set("q", q)
96+
97+
// Request -> Response
98+
if err := c.Do(nil, &response, client.OptPath("forecast.json"), client.OptQuery(request.Values)); err != nil {
99+
return Forecast{}, err
100+
} else {
101+
return response, nil
102+
}
103+
}

pkg/weatherapi/client_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,18 @@ func Test_client_002(t *testing.T) {
3030
t.Log(weather)
3131
}
3232

33+
func Test_client_003(t *testing.T) {
34+
assert := assert.New(t)
35+
client, err := weatherapi.New(GetApiKey(t), opts.OptTrace(os.Stderr, true))
36+
assert.NoError(err)
37+
38+
forecast, err := client.Forecast("Berlin, Germany", weatherapi.OptDays(2))
39+
if !assert.NoError(err) {
40+
t.SkipNow()
41+
}
42+
t.Log(forecast)
43+
}
44+
3345
///////////////////////////////////////////////////////////////////////////////
3446
// ENVIRONMENT
3547

pkg/weatherapi/opt.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package weatherapi
2+
3+
import (
4+
"fmt"
5+
"net/url"
6+
7+
// Namespace imports
8+
. "github.com/djthorpe/go-errors"
9+
)
10+
11+
////////////////////////////////////////////////////////////////////////////////
12+
// TYPES
13+
14+
type options struct {
15+
url.Values
16+
}
17+
18+
type Opt func(*options) error
19+
20+
////////////////////////////////////////////////////////////////////////////////
21+
22+
// Number of days of weather forecast. Value ranges from 1 to 10
23+
func OptDays(days int) Opt {
24+
return func(o *options) error {
25+
if days < 1 {
26+
return ErrBadParameter.With("OptDays")
27+
}
28+
o.Set("days", fmt.Sprint(days))
29+
return nil
30+
}
31+
}
32+
33+
// Get air quality data
34+
func OptAirQuality() Opt {
35+
return func(o *options) error {
36+
o.Set("aqi", "yes")
37+
return nil
38+
}
39+
}
40+
41+
// Get weather alert data
42+
func OptAlerts() Opt {
43+
return func(o *options) error {
44+
o.Set("alerts", "yes")
45+
return nil
46+
}
47+
}

pkg/weatherapi/schema.go

Lines changed: 82 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,23 @@ type Location struct {
2020
Localtime Time `json:"localtime,omitempty"`
2121
}
2222

23-
type Current struct {
24-
LastUpdatedEpoch int64 `json:"last_updated_epoch"`
25-
LastUpdated Time `json:"last_updated,omitempty"`
26-
TempC float64 `json:"temp_c"`
27-
TempF float64 `json:"temp_f"`
28-
IsDay int `json:"is_day"` // Whether to show day condition icon (1) or night icon (0)
29-
Condition struct {
23+
type CurrentConditions struct {
24+
LastUpdatedEpoch int64 `json:"last_updated_epoch"`
25+
LastUpdated Time `json:"last_updated,omitempty"`
26+
Conditions
27+
}
28+
29+
type ForecastConditions struct {
30+
TimeEpoch int64 `json:"time_epoch"`
31+
Time Time `json:"time,omitempty"`
32+
Conditions
33+
}
34+
35+
type Conditions struct {
36+
TempC float64 `json:"temp_c"`
37+
TempF float64 `json:"temp_f"`
38+
IsDay int `json:"is_day"` // Whether to show day condition icon (1) or night icon (0)
39+
Condition struct {
3040
Text string `json:"text"`
3141
Icon string `json:"icon"`
3242
Code int `json:"code"`
@@ -50,11 +60,67 @@ type Current struct {
5060
GustKph float64 `json:"gust_kph"`
5161
}
5262

63+
type Day struct {
64+
MaxTempC float64 `json:"maxtemp_c"`
65+
MaxTempF float64 `json:"maxtemp_f"`
66+
MinTempC float64 `json:"mintemp_c"`
67+
MinTempF float64 `json:"mintemp_f"`
68+
AvgTempC float64 `json:"avgtemp_c"`
69+
AvgTempF float64 `json:"avgtemp_f"`
70+
MaxWindMph float64 `json:"maxwind_mph"`
71+
MaxWindKph float64 `json:"maxwind_kph"`
72+
TotalPrecipMm float64 `json:"totalprecip_mm"`
73+
TotalPrecipIn float64 `json:"totalprecip_in"`
74+
TotalSnowCm float64 `json:"totalsnow_cm"`
75+
AvgVisKm float64 `json:"avgvis_km"`
76+
AvgVisMiles float64 `json:"avgvis_miles"`
77+
AvgHumidity int `json:"avghumidity"`
78+
WillItRain int `json:"daily_will_it_rain"`
79+
WillItSnow int `json:"daily_will_it_snow"`
80+
ChanceOfRainPercent int `json:"daily_chance_of_rain"`
81+
ChanceOfSnowPercent int `json:"daily_chance_of_snow"`
82+
Uv float32 `json:"uv"`
83+
Condition struct {
84+
Text string `json:"text"`
85+
Icon string `json:"icon"`
86+
Code int `json:"code"`
87+
} `json:"condition"`
88+
}
89+
90+
type ForecastDay struct {
91+
Date string `json:"date"`
92+
DateEpoch int64 `json:"date_epoch"`
93+
Day *Day `json:"day"`
94+
Hour []*ForecastConditions `json:"hour"`
95+
Astro *Astro `json:"astro"`
96+
}
97+
98+
type Astro struct {
99+
SunRise string `json:"sunrise"`
100+
SunSet string `json:"sunset"`
101+
MoonRise string `json:"moonrise"`
102+
MoonSet string `json:"moonset"`
103+
MoonPhase string `json:"moon_phase"`
104+
MoonIllumination int `json:"moon_illumination"`
105+
IsMoonUp int `json:"is_moon_up"`
106+
IsSunUp int `json:"is_sun_up"`
107+
}
108+
53109
type Weather struct {
54-
Id int `json:"custom_id,omitempty"`
55-
Query string `json:"q,omitempty"`
56-
Location *Location `json:"location,omitempty"`
57-
Current *Current `json:"current,omitempty"`
110+
Id int `json:"custom_id,omitempty"`
111+
Query string `json:"q,omitempty"`
112+
Location *Location `json:"location,omitempty"`
113+
Current *CurrentConditions `json:"current,omitempty"`
114+
}
115+
116+
type Forecast struct {
117+
Id int `json:"custom_id,omitempty"`
118+
Query string `json:"q,omitempty"`
119+
Location *Location `json:"location,omitempty"`
120+
Current *CurrentConditions `json:"current,omitempty"`
121+
Forecast struct {
122+
Day []*ForecastDay `json:"forecastday"`
123+
} `json:"forecast,omitempty"`
58124
}
59125

60126
type Time struct {
@@ -69,6 +135,11 @@ func (w Weather) String() string {
69135
return string(data)
70136
}
71137

138+
func (f Forecast) String() string {
139+
data, _ := json.MarshalIndent(f, "", " ")
140+
return string(data)
141+
}
142+
72143
///////////////////////////////////////////////////////////////////////////////
73144
// MARSHAL TIME
74145

0 commit comments

Comments
 (0)