Skip to content

Commit

Permalink
Merge pull request #11 from mdb/misc-optimizations
Browse files Browse the repository at this point in the history
Misc optimizations
  • Loading branch information
mdb authored Apr 4, 2023
2 parents 0590345 + 41e35a4 commit a4be773
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 32 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
SOURCE=./
VERSION=0.7.0
VERSION=0.8.0

.DEFAULT_GOAL := test

Expand Down
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,24 @@ A thin, Go [Magic Seaweed API](https://magicseaweed.com/developer/forecast-api) c

Basic usage:

```go
import (
"github.com/mdb/seaweed"
)

func main() {
forecasts, err := seaweed.Get("<YOUR_API_KEY>", "<SOME_SPOT_ID")
if err != nil {
panic(err)
}

fmt.Printf("%# v", forecasts)
}
```

Alternatively, instantiate a `seaweed.Client`:


```go
import (
"github.com/mdb/seaweed"
Expand Down
23 changes: 16 additions & 7 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,20 +62,21 @@ func WithHTTPClient(httpClient *http.Client) ClientOption {
}
}

// WithLogger is a ClientOption to configure a *Client's logger.
// WithLogger is a ClientOption to configure a *Client's Logger.
func WithLogger(l *logrus.Logger) ClientOption {
return func(c *Client) {
c.Logger = l
}
}

// WithLogger is a ClientOption to configure a *Client's clock.
func WithClock(clock Clock) ClientOption {
return func(c *Client) {
c.clock = clock
}
}

// NewClient takes an API key and returns a seaweed API client
// NewClient takes an API key and returns a seaweed API client.
func NewClient(apiKey string, opts ...ClientOption) *Client {
c := &Client{
"https://magicseaweed.com",
Expand Down Expand Up @@ -112,7 +113,7 @@ func (c *Client) Forecast(spot string) ([]Forecast, error) {

// Today fetches the today's forecast for a given spot ID.
func (c *Client) Today(spot string) ([]Forecast, error) {
today := []Forecast{}
var today []Forecast
now := c.clock.Now().UTC()
forecasts, err := c.Forecast(spot)
if err != nil {
Expand All @@ -130,7 +131,7 @@ func (c *Client) Today(spot string) ([]Forecast, error) {

// Tomorrow fetches tomorrow's forecast for a given spot ID.
func (c *Client) Tomorrow(spot string) ([]Forecast, error) {
tomorrow := []Forecast{}
var tomorrow []Forecast
tomorrowD := c.clock.Now().UTC().AddDate(0, 0, 1)
forecasts, err := c.Forecast(spot)
if err != nil {
Expand All @@ -148,7 +149,7 @@ func (c *Client) Tomorrow(spot string) ([]Forecast, error) {

// Weekend fetches the weekend's forecast for a given spot ID.
func (c *Client) Weekend(spot string) ([]Forecast, error) {
weekendFs := []Forecast{}
var weekendFs []Forecast
forecasts, err := c.Forecast(spot)
if err != nil {
return weekendFs, err
Expand Down Expand Up @@ -176,20 +177,28 @@ func (c *Client) getForecast(spotID string) ([]Forecast, error) {
var errResp APIError
err = json.Unmarshal(body, &errResp)
if err != nil {
return forecasts, err
return forecasts, fmt.Errorf("unexpected API response '%s': %w", body, err)
}

return forecasts, errors.New(errResp.ErrorResponse.ErrorMsg)
default:
err = json.Unmarshal(body, &forecasts)
if err != nil {
return forecasts, err
return forecasts, fmt.Errorf("unexpected API response '%s': %w", body, err)
}

return forecasts, nil
}
}

// Get is a convenience function that fetches the []Forecast associated with the
// location it's passed using a default Client.
func Get(key, location string) ([]Forecast, error) {
c := NewClient(key)

return c.Forecast(location)
}

func (c *Client) get(url string) ([]byte, error) {
resp, err := c.httpClient.Get(url)
if err != nil {
Expand Down
23 changes: 7 additions & 16 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"log"
"net/http"
"net/http/httptest"
"net/url"
"os"
"reflect"
"testing"
Expand Down Expand Up @@ -47,24 +46,16 @@ func (testClock) Now() time.Time {
}

func testServerAndClient(code int, body string) (*httptest.Server, *Client) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(code)
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w, body)
}))

tr := &http.Transport{
Proxy: func(req *http.Request) (*url.URL, error) {
return url.Parse(server.URL)
},
}

httpClient := &http.Client{Transport: tr}

client := NewClient(
"fakeKey",
WithBaseURL(server.URL),
WithHTTPClient(httpClient),
WithHTTPClient(server.Client()),
WithClock(testClock{}),
)

Expand Down Expand Up @@ -98,7 +89,7 @@ func TestForecast(t *testing.T) {
body: "{foo:",
code: 200,
expectForecastCount: 0,
expectError: errors.New("invalid character 'f' looking for beginning of object key string"),
expectError: errors.New("unexpected API response '{foo:': invalid character 'f' looking for beginning of object key string"),
}, {
desc: "when the response code is not OK",
body: resp,
Expand All @@ -116,7 +107,7 @@ func TestForecast(t *testing.T) {
body: "error_response{",
code: 200,
expectForecastCount: 0,
expectError: errors.New("invalid character 'e' looking for beginning of value"),
expectError: errors.New("unexpected API response 'error_response{': invalid character 'e' looking for beginning of value"),
}}

for i := range tests {
Expand Down Expand Up @@ -173,7 +164,7 @@ func TestWeekend(t *testing.T) {
body: "{foo:",
code: 200,
expectForecastCount: 0,
expectError: errors.New("invalid character 'f' looking for beginning of object key string"),
expectError: errors.New("unexpected API response '{foo:': invalid character 'f' looking for beginning of object key string"),
}, {
desc: "when the response code is not OK",
body: resp,
Expand Down Expand Up @@ -236,7 +227,7 @@ func TestToday(t *testing.T) {
body: "{foo:",
code: 200,
expectForecastCount: 0,
expectError: errors.New("invalid character 'f' looking for beginning of object key string"),
expectError: errors.New("unexpected API response '{foo:': invalid character 'f' looking for beginning of object key string"),
}, {
desc: "when the response code is not OK",
body: resp,
Expand Down Expand Up @@ -299,7 +290,7 @@ func TestTomorrow(t *testing.T) {
body: "{foo:",
code: 200,
expectForecastCount: 0,
expectError: errors.New("invalid character 'f' looking for beginning of object key string"),
expectError: errors.New("unexpected API response '{foo:': invalid character 'f' looking for beginning of object key string"),
}, {
desc: "when the response code is not OK",
body: resp,
Expand Down
12 changes: 7 additions & 5 deletions internal/integrationtest/integration_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package integrationtest

import (
"log"
"os"
"testing"
"time"
Expand All @@ -11,7 +12,12 @@ import (
var client *seaweed.Client

func TestMain(m *testing.M) {
client = seaweed.NewClient(os.Getenv("MAGIC_SEAWEED_API_KEY"))
key := os.Getenv("MAGIC_SEAWEED_API_KEY")
if key == "" {
log.Fatal("MAGIC_SEAWEED_API_KEY environment variable not set")
}

client = seaweed.NewClient(key)
exitVal := m.Run()
os.Exit(exitVal)
}
Expand Down Expand Up @@ -92,10 +98,6 @@ func TestWeekend_Integration(t *testing.T) {
t.Error(err)
}

if len(resp) == 0 {
t.Error("API returned no forecasts")
}

for _, forecast := range resp {
fd := time.Unix(forecast.LocalTimestamp, 0).UTC().Weekday().String()

Expand Down
18 changes: 15 additions & 3 deletions resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type Forecast struct {
Swell Swell `json:"swell"`
Wind Wind `json:"wind"`
Condition Condition `json:"condition"`
Charts Charts `json:"charts"`
}

// IsWeekend returns true if a forecast pertains to a Saturday or a Sunday.
Expand All @@ -52,14 +53,17 @@ type Swell struct {
AbsMinBreakingHeight float64 `json:"absMinBreakingHeight"`
MaxBreakingHeight int `json:"maxBreakingHeight"`
AbsMaxBreakingHeight float64 `json:"absMaxBreakingHeight"`
Probability int `json:"probability"`
Unit string `json:"unit"`
Components Components `json:"components"`
}

// Components represents a Seaweed API forecast's swell's components.
type Components struct {
Combined Component `json:"combined"`
Primary Component `json:"primary"`
Combined Component `json:"combined"`
Primary Component `json:"primary"`
Secondary Component `json:"secondary"`
Tertiary Component `json:"tertiary"`
}

// Component represents a Seaweed API forecast's swell component.
Expand All @@ -85,6 +89,14 @@ type Condition struct {
Pressure int64 `json:"pressure"`
Temperature int64 `json:"temperature"`
Weather string `json:"weather"`
Unit string `json:"f"`
Unit string `json:"unit"`
UnitPressure string `json:"unitPressure"`
}

// Charts represents a Seaweed API forecast's charts.
type Charts struct {
Swell string `json:"swell"`
Period string `json:"period"`
Wind string `json:"wind"`
Pressure string `json:"pressure"`
}

0 comments on commit a4be773

Please sign in to comment.