mirror of
https://github.com/imjasonh/staticmaps
synced 2026-07-09 03:15:09 +00:00
remove Client struct, use context values for API key, Work client ID and private key, and http Client
This commit is contained in:
parent
9166c9bae7
commit
64ec22f709
10 changed files with 127 additions and 97 deletions
67
context.go
Normal file
67
context.go
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
package maps
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"code.google.com/p/go.net/context"
|
||||
)
|
||||
|
||||
type contextKey int
|
||||
|
||||
// NewContext returns a new context that uses the provided http.Client and API key.
|
||||
func NewContext(key string, c *http.Client) context.Context {
|
||||
return WithContext(context.Background(), key, c)
|
||||
}
|
||||
|
||||
// WithContext returns a new context in a similar way NewContext does, but initiates the new context with the specified parent.
|
||||
func WithContext(parent context.Context, key string, c *http.Client) context.Context {
|
||||
vals := map[string]interface{}{}
|
||||
vals["key"] = key
|
||||
vals["httpClient"] = c
|
||||
return context.WithValue(parent, contextKey(0), vals)
|
||||
}
|
||||
|
||||
// NewWorkContext returns a new context that uses the provided http.Client and Google Maps API for Work client ID and private key.
|
||||
func NewWorkContext(clientID, privateKey string, c *http.Client) context.Context {
|
||||
return WithWorkCredentials(context.Background(), clientID, privateKey, c)
|
||||
}
|
||||
|
||||
// WithWorkCredentials returns a new context in a similar way NewWorkContext does, but initiates the new context with the specified parent.
|
||||
func WithWorkCredentials(parent context.Context, clientID, privateKey string, c *http.Client) context.Context {
|
||||
vals := map[string]interface{}{}
|
||||
vals["workClientID"] = clientID
|
||||
vals["workPrivKey"] = privateKey
|
||||
vals["httpClient"] = c
|
||||
return context.WithValue(parent, contextKey(0), vals)
|
||||
}
|
||||
|
||||
func key(ctx context.Context) string {
|
||||
k, found := ctx.Value(contextKey(0)).(map[string]interface{})["key"]
|
||||
if found {
|
||||
return k.(string)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func workCreds(ctx context.Context) (string, string) {
|
||||
var clientID string
|
||||
cid, found := ctx.Value(contextKey(0)).(map[string]interface{})["workClientID"]
|
||||
if found {
|
||||
clientID = cid.(string)
|
||||
}
|
||||
|
||||
var privateKey string
|
||||
pkey, found := ctx.Value(contextKey(0)).(map[string]interface{})["workPrivKey"]
|
||||
if found {
|
||||
privateKey = pkey.(string)
|
||||
}
|
||||
return clientID, privateKey
|
||||
}
|
||||
|
||||
func httpClient(ctx context.Context) *http.Client {
|
||||
cl, found := ctx.Value(contextKey(0)).(map[string]interface{})["httpClient"]
|
||||
if found && cl != nil {
|
||||
return cl.(*http.Client)
|
||||
}
|
||||
return &http.Client{Transport: &backoff{Transport: http.DefaultTransport}}
|
||||
}
|
||||
|
|
@ -37,9 +37,9 @@ const (
|
|||
// Directions requests routes between orig and dest Locations.
|
||||
//
|
||||
// See https://developers.google.com/maps/documentation/directions/
|
||||
func (c Client) Directions(ctx context.Context, orig, dest Location, opts *DirectionsOpts) ([]Route, error) {
|
||||
func Directions(ctx context.Context, orig, dest Location, opts *DirectionsOpts) ([]Route, error) {
|
||||
var d directionsResponse
|
||||
if err := c.doDecode(ctx, baseURL+directions(orig, dest, opts), &d); err != nil {
|
||||
if err := doDecode(ctx, baseURL+directions(orig, dest, opts), &d); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if d.Status != StatusOK {
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ import (
|
|||
// DistanceMatrix requests travel distance and time for a matrix of origins and destinations.
|
||||
//
|
||||
// See https://developers.google.com/maps/documentation/distancematrix/
|
||||
func (c Client) DistanceMatrix(ctx context.Context, orig, dest []Location, opts *DistanceMatrixOpts) (*DistanceMatrixResult, error) {
|
||||
func DistanceMatrix(ctx context.Context, orig, dest []Location, opts *DistanceMatrixOpts) (*DistanceMatrixResult, error) {
|
||||
var d distanceResponse
|
||||
if err := c.doDecode(ctx, baseURL+distancematrix(orig, dest, opts), &d); err != nil {
|
||||
if err := doDecode(ctx, baseURL+distancematrix(orig, dest, opts), &d); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if d.Status != StatusOK {
|
||||
|
|
|
|||
16
elevation.go
16
elevation.go
|
|
@ -10,9 +10,9 @@ import (
|
|||
// Elevation requests elevation data for a series of locations.
|
||||
//
|
||||
// See https://developers.google.com/maps/documentation/elevation/
|
||||
func (c Client) Elevation(ctx context.Context, ll []LatLng) ([]ElevationResult, error) {
|
||||
func Elevation(ctx context.Context, ll []LatLng) ([]ElevationResult, error) {
|
||||
var r elevationResponse
|
||||
if err := c.doDecode(ctx, baseURL+elevation(ll), &r); err != nil {
|
||||
if err := doDecode(ctx, baseURL+elevation(ll), &r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Status != StatusOK {
|
||||
|
|
@ -24,9 +24,9 @@ func (c Client) Elevation(ctx context.Context, ll []LatLng) ([]ElevationResult,
|
|||
// ElevationPolyline requests elevation data for a series of locations as specified as an encoded polyline.
|
||||
//
|
||||
// See https://developers.google.com/maps/documentation/elevation/#Locations
|
||||
func (c Client) ElevationPolyline(ctx context.Context, p string) ([]ElevationResult, error) {
|
||||
func ElevationPolyline(ctx context.Context, p string) ([]ElevationResult, error) {
|
||||
var r elevationResponse
|
||||
if err := c.doDecode(ctx, baseURL+elevationpoly(p), &r); err != nil {
|
||||
if err := doDecode(ctx, baseURL+elevationpoly(p), &r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Status != StatusOK {
|
||||
|
|
@ -36,9 +36,9 @@ func (c Client) ElevationPolyline(ctx context.Context, p string) ([]ElevationRes
|
|||
}
|
||||
|
||||
// ElevationPath requests elevation data for a number of samples along a path described as a series of locations.
|
||||
func (c Client) ElevationPath(ctx context.Context, ll []LatLng, samples int) ([]ElevationResult, error) {
|
||||
func ElevationPath(ctx context.Context, ll []LatLng, samples int) ([]ElevationResult, error) {
|
||||
var r elevationResponse
|
||||
if err := c.doDecode(ctx, baseURL+elevationpath(ll, samples), &r); err != nil {
|
||||
if err := doDecode(ctx, baseURL+elevationpath(ll, samples), &r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Status != StatusOK {
|
||||
|
|
@ -48,9 +48,9 @@ func (c Client) ElevationPath(ctx context.Context, ll []LatLng, samples int) ([]
|
|||
}
|
||||
|
||||
// ElevationPathPoly requests elevation data for a number of samples along a path described as a series of locations specified as an encoded polyline.
|
||||
func (c Client) ElevationPathPoly(ctx context.Context, p string, samples int) ([]ElevationResult, error) {
|
||||
func ElevationPathPoly(ctx context.Context, p string, samples int) ([]ElevationResult, error) {
|
||||
var r elevationResponse
|
||||
if err := c.doDecode(ctx, baseURL+elevationpathpoly(p, samples), &r); err != nil {
|
||||
if err := doDecode(ctx, baseURL+elevationpathpoly(p, samples), &r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Status != StatusOK {
|
||||
|
|
|
|||
|
|
@ -33,9 +33,9 @@ const (
|
|||
)
|
||||
|
||||
// Geocode requests conversion of an address to a latitude/longitude pair.
|
||||
func (c Client) Geocode(ctx context.Context, opts *GeocodeOpts) ([]GeocodeResult, error) {
|
||||
func Geocode(ctx context.Context, opts *GeocodeOpts) ([]GeocodeResult, error) {
|
||||
var r geocodeResponse
|
||||
if err := c.doDecode(ctx, baseURL+geocode(opts), &r); err != nil {
|
||||
if err := doDecode(ctx, baseURL+geocode(opts), &r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Status != StatusOK {
|
||||
|
|
@ -194,9 +194,9 @@ type GeocodeResult struct {
|
|||
// ReverseGeocode requests conversion of a location to its nearest address.
|
||||
//
|
||||
// See https://developers.google.com/maps/documentation/geocoding/#ReverseGeocoding
|
||||
func (c Client) ReverseGeocode(ctx context.Context, ll LatLng, opts *ReverseGeocodeOpts) ([]GeocodeResult, error) {
|
||||
func ReverseGeocode(ctx context.Context, ll LatLng, opts *ReverseGeocodeOpts) ([]GeocodeResult, error) {
|
||||
var r geocodeResponse
|
||||
if err := c.doDecode(ctx, baseURL+reversegeocode(ll, opts), &r); err != nil {
|
||||
if err := doDecode(ctx, baseURL+reversegeocode(ll, opts), &r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Status != StatusOK {
|
||||
|
|
|
|||
64
maps.go
64
maps.go
|
|
@ -35,61 +35,23 @@ const (
|
|||
StatusOverQueryLimit = "OVER_QUERY_LIMIT"
|
||||
)
|
||||
|
||||
// Client provides methods to make requests of various Maps APIs.
|
||||
type Client struct {
|
||||
// The underlying http.RoundTripper to use. If this is not specified, http.DefaultTransport will be used.
|
||||
Transport http.RoundTripper
|
||||
|
||||
// Key is the API key to use to authorize requests.
|
||||
Key string
|
||||
|
||||
// ClientID is the Google Maps API for Work client ID to use.
|
||||
//
|
||||
// See https://developers.google.com/maps/documentation/business/webservices/auth
|
||||
ClientID string
|
||||
|
||||
// PrivateKey is the base64-encoded private key to use for Google Maps API for Work requests.
|
||||
//
|
||||
// See https://developers.google.com/maps/documentation/business/webservices/auth
|
||||
PrivateKey string
|
||||
}
|
||||
|
||||
// New returns a Client using the specified API key and RoundTripper.
|
||||
func New(key string, rt http.RoundTripper) Client {
|
||||
return Client{Key: key, Transport: rt}
|
||||
}
|
||||
|
||||
// NewForWork returns a Client using the specified Google Maps API for Work client ID and signature, and RoundTripper.
|
||||
//
|
||||
// See https://developers.google.com/maps/documentation/business/
|
||||
func NewForWork(clientID, privateKey string, rt http.RoundTripper) Client {
|
||||
return Client{ClientID: clientID, PrivateKey: privateKey, Transport: rt}
|
||||
}
|
||||
|
||||
func (c Client) do(ctx context.Context, url string) (*http.Response, error) {
|
||||
// TODO: Use ctx here.
|
||||
|
||||
t := c.Transport
|
||||
if t == nil {
|
||||
t = http.DefaultTransport
|
||||
}
|
||||
cl := &http.Client{Transport: &backoff{
|
||||
Transport: t,
|
||||
}}
|
||||
func do(ctx context.Context, url string) (*http.Response, error) {
|
||||
cl := httpClient(ctx)
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
q := req.URL.Query()
|
||||
if c.Key != "" {
|
||||
q.Set("key", c.Key)
|
||||
if k := key(ctx); k != "" {
|
||||
q.Set("key", k)
|
||||
}
|
||||
if c.ClientID != "" {
|
||||
q.Set("client", c.ClientID)
|
||||
clientID, privKey := workCreds(ctx)
|
||||
if clientID != "" {
|
||||
q.Set("client", clientID)
|
||||
}
|
||||
enc := q.Encode()
|
||||
if c.PrivateKey != "" {
|
||||
sig, err := c.genSig(req.URL.Path, enc)
|
||||
if privKey != "" {
|
||||
sig, err := genSig(privKey, req.URL.Path, enc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -100,9 +62,9 @@ func (c Client) do(ctx context.Context, url string) (*http.Response, error) {
|
|||
}
|
||||
|
||||
// See https://developers.google.com/maps/documentation/business/webservices/auth
|
||||
func (c Client) genSig(path, query string) (string, error) {
|
||||
func genSig(privKey, path, query string) (string, error) {
|
||||
toSign := path + "?" + query
|
||||
decodedKey, err := base64.URLEncoding.DecodeString(c.PrivateKey)
|
||||
decodedKey, err := base64.URLEncoding.DecodeString(privKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
@ -113,8 +75,8 @@ func (c Client) genSig(path, query string) (string, error) {
|
|||
return base64.URLEncoding.EncodeToString(d.Sum(nil)), nil
|
||||
}
|
||||
|
||||
func (c Client) doDecode(ctx context.Context, url string, r interface{}) error {
|
||||
resp, err := c.do(ctx, url)
|
||||
func doDecode(ctx context.Context, url string, r interface{}) error {
|
||||
resp, err := do(ctx, url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
49
maps_test.go
49
maps_test.go
|
|
@ -2,16 +2,17 @@ package maps
|
|||
|
||||
import (
|
||||
"image/color"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.google.com/p/go.net/context"
|
||||
)
|
||||
|
||||
var ctx = context.Background()
|
||||
var (
|
||||
ctx = NewContext("key", &http.Client{})
|
||||
wctx = NewWorkContext("clientID", "privKey", &http.Client{})
|
||||
)
|
||||
|
||||
func TestDirections(t *testing.T) {
|
||||
c := New("", nil)
|
||||
orig, dest := Address("111 8th Ave, NYC"), Address("170 E 92nd St, NYC")
|
||||
opts := &DirectionsOpts{
|
||||
Mode: ModeTransit,
|
||||
|
|
@ -19,7 +20,7 @@ func TestDirections(t *testing.T) {
|
|||
Alternatives: true,
|
||||
}
|
||||
t.Logf("%s", baseURL+directions(orig, dest, opts))
|
||||
r, err := c.Directions(ctx, orig, dest, opts)
|
||||
r, err := Directions(ctx, orig, dest, opts)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
|
@ -27,7 +28,6 @@ func TestDirections(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestStaticMap(t *testing.T) {
|
||||
c := New("", nil)
|
||||
s := Size{512, 512}
|
||||
opts := &StaticMapOpts{
|
||||
Center: LatLng{-5, -5},
|
||||
|
|
@ -77,13 +77,12 @@ func TestStaticMap(t *testing.T) {
|
|||
},
|
||||
}
|
||||
t.Logf("%s", baseURL+staticmap(s, opts))
|
||||
if _, err := c.StaticMap(ctx, s, opts); err != nil {
|
||||
if _, err := StaticMap(ctx, s, opts); err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStreetView(t *testing.T) {
|
||||
c := New("", nil)
|
||||
s := Size{600, 300}
|
||||
opts := &StreetViewOpts{
|
||||
Location: &LatLng{46.414382, 10.013988},
|
||||
|
|
@ -91,17 +90,16 @@ func TestStreetView(t *testing.T) {
|
|||
Pitch: -0.76,
|
||||
}
|
||||
t.Logf("%s", baseURL+streetview(s, opts))
|
||||
if _, err := c.StreetView(ctx, s, opts); err != nil {
|
||||
if _, err := StreetView(ctx, s, opts); err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimeZone(t *testing.T) {
|
||||
c := New("", nil)
|
||||
ll := LatLng{40.7142700, -74.0059700}
|
||||
tm := time.Now()
|
||||
t.Logf("%s", baseURL+timezone(ll, tm, nil))
|
||||
r, err := c.TimeZone(ctx, ll, tm, nil)
|
||||
r, err := TimeZone(ctx, ll, tm, nil)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
|
@ -109,10 +107,9 @@ func TestTimeZone(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestElevation(t *testing.T) {
|
||||
c := New("", nil)
|
||||
ll := []LatLng{{39.7391536, -104.9847034}}
|
||||
t.Logf("%s", baseURL+elevation(ll))
|
||||
r, err := c.Elevation(ctx, ll)
|
||||
r, err := Elevation(ctx, ll)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
|
@ -120,7 +117,7 @@ func TestElevation(t *testing.T) {
|
|||
|
||||
p := "gfo}EtohhU"
|
||||
t.Logf("%s", baseURL+elevationpoly(p))
|
||||
r, err = c.ElevationPolyline(ctx, p)
|
||||
r, err = ElevationPolyline(ctx, p)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
|
@ -129,7 +126,7 @@ func TestElevation(t *testing.T) {
|
|||
samples := 3
|
||||
ll = []LatLng{{36.578581, -118.291994}, {36.23998, -116.83171}}
|
||||
t.Logf("%s", baseURL+elevationpath(ll, samples))
|
||||
r, err = c.ElevationPath(ctx, ll, samples)
|
||||
r, err = ElevationPath(ctx, ll, samples)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
|
@ -137,7 +134,7 @@ func TestElevation(t *testing.T) {
|
|||
|
||||
p = "gfo}EtohhUxD@bAxJmGF"
|
||||
t.Logf("%s", baseURL+elevationpathpoly(p, samples))
|
||||
r, err = c.ElevationPathPoly(ctx, p, samples)
|
||||
r, err = ElevationPathPoly(ctx, p, samples)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
|
@ -145,12 +142,11 @@ func TestElevation(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGeocode(t *testing.T) {
|
||||
c := New("", nil)
|
||||
opts := &GeocodeOpts{
|
||||
Address: Address("1600 Amphitheatre Parkway, Mountain View, CA"),
|
||||
}
|
||||
t.Logf("%s", baseURL+geocode(opts))
|
||||
r, err := c.Geocode(ctx, opts)
|
||||
r, err := Geocode(ctx, opts)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
|
@ -158,7 +154,7 @@ func TestGeocode(t *testing.T) {
|
|||
|
||||
ll := LatLng{40.714224, -73.961452}
|
||||
t.Logf("%s", baseURL+reversegeocode(ll, nil))
|
||||
r, err = c.ReverseGeocode(ctx, ll, nil)
|
||||
r, err = ReverseGeocode(ctx, ll, nil)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
|
@ -166,7 +162,6 @@ func TestGeocode(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDistanceMatrix(t *testing.T) {
|
||||
c := New("", nil)
|
||||
orig := []Location{Address("Vancouver, BC"), Address("Seattle")}
|
||||
dst := []Location{Address("San Francisco"), Address("Victoria, BC")}
|
||||
opts := &DistanceMatrixOpts{
|
||||
|
|
@ -174,7 +169,7 @@ func TestDistanceMatrix(t *testing.T) {
|
|||
Language: "fr-FR",
|
||||
}
|
||||
t.Logf("%s", baseURL+distancematrix(orig, dst, opts))
|
||||
r, err := c.DistanceMatrix(ctx, orig, dst, opts)
|
||||
r, err := DistanceMatrix(ctx, orig, dst, opts)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
|
@ -184,13 +179,19 @@ func TestDistanceMatrix(t *testing.T) {
|
|||
|
||||
// Based on https://developers.google.com/maps/documentation/business/webservices/auth#signature_examples
|
||||
func TestSignature(t *testing.T) {
|
||||
c := NewForWork("", "vNIXE0xscrmjlyV-12Nj_BvUPaw=", nil)
|
||||
sig, err := c.genSig("/maps/api/geocode/json", "address=New+York&client=clientID")
|
||||
clientID := "clientID"
|
||||
privateKey := "vNIXE0xscrmjlyV-12Nj_BvUPaw="
|
||||
sig, err := genSig(privateKey, "/maps/api/geocode/json", "address=New+York&client="+clientID)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
exp := "chaRF2hTJKOScPr-RQCEhZbSzIE="
|
||||
if sig != exp {
|
||||
t.Errorf("wrong signature, got %q, want %q", sig, exp)
|
||||
t.Errorf("unexpected signature, got %q, want %q", sig, exp)
|
||||
}
|
||||
|
||||
ctx := NewWorkContext(clientID, privateKey, nil)
|
||||
if gcid, gkey := workCreds(ctx); gcid != clientID || gkey != privateKey {
|
||||
t.Errorf("unepxected credentials from context, got %q and %q, want %q and %q", gcid, gkey, clientID, privateKey)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@ const (
|
|||
)
|
||||
|
||||
// StaticMap requests a static map image of a requested size.
|
||||
func (c Client) StaticMap(ctx context.Context, s Size, opts *StaticMapOpts) (io.ReadCloser, error) {
|
||||
resp, err := c.do(ctx, baseURL+staticmap(s, opts))
|
||||
func StaticMap(ctx context.Context, s Size, opts *StaticMapOpts) (io.ReadCloser, error) {
|
||||
resp, err := do(ctx, baseURL+staticmap(s, opts))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ import (
|
|||
)
|
||||
|
||||
// StreetView requests a static StreetView image of the requested size.
|
||||
func (c Client) StreetView(ctx context.Context, s Size, opts *StreetViewOpts) (io.ReadCloser, error) {
|
||||
resp, err := c.do(ctx, baseURL+streetview(s, opts))
|
||||
func StreetView(ctx context.Context, s Size, opts *StreetViewOpts) (io.ReadCloser, error) {
|
||||
resp, err := do(ctx, baseURL+streetview(s, opts))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ import (
|
|||
// TimeZone requests time zone information about a location.
|
||||
//
|
||||
// See https://developers.google.com/maps/documentation/timezone/
|
||||
func (c Client) TimeZone(ctx context.Context, ll LatLng, t time.Time, opts *TimeZoneOpts) (*TimeZoneResult, error) {
|
||||
func TimeZone(ctx context.Context, ll LatLng, t time.Time, opts *TimeZoneOpts) (*TimeZoneResult, error) {
|
||||
var r timeZoneResponse
|
||||
if err := c.doDecode(ctx, baseURL+timezone(ll, t, opts), &r); err != nil {
|
||||
if err := doDecode(ctx, baseURL+timezone(ll, t, opts), &r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if r.Status != StatusOK {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue