Skip to content

Commit

Permalink
feat: support experience id header (#224)
Browse files Browse the repository at this point in the history
  • Loading branch information
jpoehnelt authored Jan 21, 2020
1 parent 462e152 commit 64b798d
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 0 deletions.
39 changes: 39 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"io"
"net/http"
"net/url"
"strings"

"golang.org/x/time/rate"
"googlemaps.github.io/maps/internal"
Expand All @@ -39,13 +40,18 @@ type Client struct {
requestsPerSecond int
rateLimiter *rate.Limiter
channel string
experienceId []string
}

// ClientOption is the type of constructor options for NewClient(...).
type ClientOption func(*Client) error

var defaultRequestsPerSecond = 50

const (
ExperienceIdHeaderName = "X-GOOG-MAPS-EXPERIENCE-ID"
)

// NewClient constructs a new Client which can make requests to the Google Maps
// WebService APIs.
func NewClient(options ...ClientOption) (*Client, error) {
Expand Down Expand Up @@ -146,6 +152,15 @@ func WithRateLimit(requestsPerSecond int) ClientOption {
}
}

// WithExperienceId configures the client with an initial experience id that
// can be changed with the `setExperienceId` method.
func WithExperienceId(ids ...string) ClientOption {
return func(c *Client) error {
c.experienceId = ids
return nil
}
}

type apiConfig struct {
host string
path string
Expand Down Expand Up @@ -177,6 +192,9 @@ func (c *Client) get(ctx context.Context, config *apiConfig, apiReq apiRequest)
if err != nil {
return nil, err
}

c.setExperienceIdHeader(req)

q, err := c.generateAuthQuery(config.path, apiReq.params(), config.acceptsClientID, config.acceptsSignature)
if err != nil {
return nil, err
Expand Down Expand Up @@ -204,6 +222,9 @@ func (c *Client) post(ctx context.Context, config *apiConfig, apiReq interface{}
return nil, err
}
req.Header.Set("Content-Type", "application/json")

c.setExperienceIdHeader(req)

q, err := c.generateAuthQuery(config.path, url.Values{}, config.acceptsClientID, config.acceptsSignature)
if err != nil {
return nil, err
Expand Down Expand Up @@ -241,6 +262,24 @@ func (c *Client) postJSON(ctx context.Context, config *apiConfig, apiReq interfa
return json.NewDecoder(httpResp.Body).Decode(resp)
}

func (c *Client) setExperienceId(ids ...string) {
c.experienceId = ids
}

func (c *Client) getExperienceId() []string {
return c.experienceId
}

func (c *Client) clearExperienceId() {
c.experienceId = nil
}

func (c *Client) setExperienceIdHeader(req *http.Request) {
if len(c.experienceId) > 0 {
req.Header.Set(ExperienceIdHeaderName, strings.Join(c.experienceId, ","))
}
}

type binaryResponse struct {
statusCode int
contentType string
Expand Down
85 changes: 85 additions & 0 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@
package maps

import (
"net/http"
"strings"
"testing"

"github.com/google/uuid"
"github.com/stretchr/testify/assert"
)

func TestClientChannelIsConfigured(t *testing.T) {
Expand All @@ -24,3 +29,83 @@ func TestClientChannelIsConfigured(t *testing.T) {
t.Errorf("Unable to create client with channel")
}
}

func TestClientWithExperienceId(t *testing.T) {
ids := []string{"foo", "bar"}
c, err := NewClient(WithAPIKey("AIza-Maps-API-Key"), WithExperienceId(ids...))
assert.Nil(t, err)
assert.Equal(t, c.experienceId, ids)
}

func TestClientSetExperienceId(t *testing.T) {
ids := []string{"foo", "bar"}
c, _ := NewClient(WithAPIKey("AIza-Maps-API-Key"))

c.setExperienceId(ids...)
assert.Equal(t, c.experienceId, ids)
}

func TestClientGetExperienceId(t *testing.T) {
ids := []string{"foo", "bar"}
c, _ := NewClient(WithAPIKey("AIza-Maps-API-Key"))

c.experienceId = ids
assert.Equal(t, c.getExperienceId(), ids)
}

func TestClientClearExperienceId(t *testing.T) {
ids := []string{"foo", "bar"}
c, _ := NewClient(WithAPIKey("AIza-Maps-API-Key"))

c.experienceId = ids
c.clearExperienceId()
assert.Nil(t, c.experienceId)
}

func TestClientSetExperienceIdHeader(t *testing.T) {
ids := []string{"foo", "bar"}
c, _ := NewClient(WithAPIKey("AIza-Maps-API-Key"))

// slice has two elements
c.experienceId = ids
req, _ := http.NewRequest("GET", "/", nil)
c.setExperienceIdHeader(req)
assert.Equal(t, req.Header.Get(ExperienceIdHeaderName), strings.Join(ids, ","))

// slice is nil
c.experienceId = nil
req, _ = http.NewRequest("GET", "/", nil)
c.setExperienceIdHeader(req)
assert.Equal(t, req.Header.Get(ExperienceIdHeaderName), "")

// slice is empty
c.experienceId = []string{}
req, _ = http.NewRequest("GET", "/", nil)
c.setExperienceIdHeader(req)
assert.Equal(t, req.Header.Get(ExperienceIdHeaderName), "")
}

func TestClientExperienceIdSample(t *testing.T) {
// [START maps_experience_id]
experienceId := uuid.New().String()

// instantiate client with experience id
client, _ := NewClient(WithAPIKey("AIza-Maps-API-Key"), WithExperienceId("foo"))

// clear the current experience id
client.clearExperienceId()

// set a new experience id
otherExperienceId := uuid.New().String()
client.setExperienceId(experienceId, otherExperienceId)

// make API request, the client will set the header
// X-GOOG-MAPS-EXPERIENCE-ID: experienceId,otherExperienceId

// get current experience id
var ids []string
ids = client.getExperienceId()
// [END maps_experience_id]

assert.Equal(t, ids, []string{experienceId, otherExperienceId})
}

0 comments on commit 64b798d

Please sign in to comment.