From c240dc9e0b53a6439f36598482c3f0e99db293b7 Mon Sep 17 00:00:00 2001 From: Xan Johnson Date: Tue, 10 Oct 2023 16:51:38 -0600 Subject: [PATCH] Support intl autocomplete v2 --- .../international-autocomplete-api/main.go | 6 +- international-autocomplete-api/candidate.go | 16 ++--- international-autocomplete-api/client.go | 9 ++- international-autocomplete-api/client_test.go | 61 ++++++++++-------- international-autocomplete-api/lookup.go | 63 +++---------------- international-autocomplete-api/lookup_test.go | 47 ++------------ wireup/builder.go | 2 +- 7 files changed, 69 insertions(+), 135 deletions(-) diff --git a/examples/international-autocomplete-api/main.go b/examples/international-autocomplete-api/main.go index aea6dd9..b55d981 100644 --- a/examples/international-autocomplete-api/main.go +++ b/examples/international-autocomplete-api/main.go @@ -34,7 +34,11 @@ func main() { log.Fatal("Error sending batch:", err) } - fmt.Printf("Results for input: [%s]\n", lookup.Search) + if len(lookup.Search) > 0 { + fmt.Printf("Results for input: [%s]\n", lookup.Search) + } else { + fmt.Printf("Results for input: [%s]\n", lookup.AddressID) + } for s, candidate := range lookup.Result.Candidates { fmt.Printf("#%d: %#v\n", s, candidate) } diff --git a/international-autocomplete-api/candidate.go b/international-autocomplete-api/candidate.go index 4dd0e85..6bd36a5 100644 --- a/international-autocomplete-api/candidate.go +++ b/international-autocomplete-api/candidate.go @@ -1,11 +1,13 @@ package international_autocomplete_api type Candidate struct { - Street string `json:"street"` - Locality string `json:"locality"` - AdministrativeArea string `json:"administrative_area"` - SuperAdministrativeArea string `json:"super_administrative_area"` - SubAdministrativeArea string `json:"sub_administrative_area"` - PostalCode string `json:"postal_code"` - CountryIso3 string `json:"country_iso3"` + Street string `json:"street"` + Locality string `json:"locality"` + AdministrativeArea string `json:"administrative_area"` + PostalCode string `json:"postal_code"` + CountryIso3 string `json:"country_iso3"` + + Entries int `json:"entries"` + AddressText string `json:"address_text"` + AddressID string `json:"address_id"` } diff --git a/international-autocomplete-api/client.go b/international-autocomplete-api/client.go index 661dab3..6e2d812 100644 --- a/international-autocomplete-api/client.go +++ b/international-autocomplete-api/client.go @@ -22,7 +22,7 @@ func (c *Client) SendLookup(lookup *Lookup) error { } func (c *Client) SendLookupWithContext(ctx context.Context, lookup *Lookup) error { - if lookup == nil || len(lookup.Search) == 0 { + if lookup == nil || len(lookup.Country) == 0 || (len(lookup.Search) == 0 && len(lookup.AddressID) == 0) { return nil } @@ -45,11 +45,16 @@ func deserializeResponse(response []byte, lookup *Lookup) error { } func buildRequest(lookup *Lookup) *http.Request { - request, _ := http.NewRequest("GET", suggestURL, nil) // We control the method and the URL. This is safe. + var addressID = "" + if len(lookup.AddressID) > 0 { + addressID = "/" + lookup.AddressID + } + request, _ := http.NewRequest("GET", suggestURL+addressID, nil) // We control the method and the URL. This is safe. query := request.URL.Query() lookup.populate(query) request.URL.RawQuery = query.Encode() return request } +// TODO support /lookup and /v2/lookup const suggestURL = "/lookup" // Remaining parts will be completed later by the sdk.BaseURLClient. diff --git a/international-autocomplete-api/client_test.go b/international-autocomplete-api/client_test.go index bc5954a..488a5e5 100644 --- a/international-autocomplete-api/client_test.go +++ b/international-autocomplete-api/client_test.go @@ -36,23 +36,20 @@ func (f *ClientFixture) TestAddressLookupSerializedAndSentWithContext__ResponseS "street": "1", "locality": "2", "administrative_area": "3", - "super_administrative_area": "4", - "sub_administrative_area": "5", - "postal_code": "6", - "country_iso3": "7" + "postal_code": "4", + "country_iso3": "5" }, { - "street": "8", - "locality": "9", - "administrative_area": "10", - "super_administrative_area": "11", - "sub_administrative_area": "12", - "postal_code": "13", - "country_iso3": "14" + "street": "6", + "locality": "7", + "administrative_area": "8", + "postal_code": "9", + "country_iso3": "10" } ] }` f.input.Search = "42" + f.input.Country = "FRA" ctx := context.WithValue(context.Background(), "key", "value") err := f.client.SendLookupWithContext(ctx, f.input) @@ -62,27 +59,23 @@ func (f *ClientFixture) TestAddressLookupSerializedAndSentWithContext__ResponseS f.So(f.sender.request.Method, should.Equal, "GET") f.So(f.sender.request.URL.Path, should.Equal, suggestURL) f.So(f.sender.request.URL.Query().Get("search"), should.Equal, "42") - f.So(f.sender.request.URL.String(), should.Equal, suggestURL+"?distance=5&max_results=5&search=42") + f.So(f.sender.request.URL.String(), should.Equal, suggestURL+"?country=FRA&max_results=5&search=42") f.So(f.sender.request.Context(), should.Resemble, ctx) f.So(f.input.Result, should.Resemble, &Result{Candidates: []*Candidate{ { - Street: "1", - Locality: "2", - AdministrativeArea: "3", - SuperAdministrativeArea: "4", - SubAdministrativeArea: "5", - PostalCode: "6", - CountryIso3: "7", + Street: "1", + Locality: "2", + AdministrativeArea: "3", + PostalCode: "4", + CountryIso3: "5", }, { - Street: "8", - Locality: "9", - AdministrativeArea: "10", - SuperAdministrativeArea: "11", - SubAdministrativeArea: "12", - PostalCode: "13", - CountryIso3: "14", + Street: "6", + Locality: "7", + AdministrativeArea: "8", + PostalCode: "9", + CountryIso3: "10", }, }}) } @@ -106,6 +99,7 @@ func (f *ClientFixture) TestSenderErrorPreventsDeserialization() { {"text": "3"} ]}` // would be deserialized if not for the err (above) f.input.Search = "HI" + f.input.Country = "FRA" err := f.client.SendLookup(f.input) @@ -116,6 +110,7 @@ func (f *ClientFixture) TestSenderErrorPreventsDeserialization() { func (f *ClientFixture) TestDeserializationErrorPreventsDeserialization() { f.sender.response = `I can't haz JSON` f.input.Search = "HI" + f.input.Country = "FRA" err := f.client.SendLookup(f.input) @@ -123,6 +118,20 @@ func (f *ClientFixture) TestDeserializationErrorPreventsDeserialization() { f.So(f.input.Result, should.BeNil) } +func (f *ClientFixture) TestAddressIDAppendsToURL() { + f.input.Country = "FRA" + f.input.AddressID = "thisisid" + + err := f.client.SendLookup(f.input) + + f.So(err, should.NotBeNil) + + f.So(f.sender.request, should.NotBeNil) + f.So(f.sender.request.Method, should.Equal, "GET") + f.So(f.sender.request.URL.Path, should.Equal, suggestURL+"/thisisid") + f.So(f.sender.request.URL.String(), should.Equal, suggestURL+"/thisisid?country=FRA&max_results=5") +} + ////////////////////////////////////////////////////////////////// type FakeSender struct { diff --git a/international-autocomplete-api/lookup.go b/international-autocomplete-api/lookup.go index b714c30..486d8f0 100644 --- a/international-autocomplete-api/lookup.go +++ b/international-autocomplete-api/lookup.go @@ -1,7 +1,6 @@ package international_autocomplete_api import ( - "math" "net/url" "strconv" ) @@ -12,30 +11,21 @@ const ( ) type Lookup struct { - Country string - Search string - MaxResults int - Distance int - Geolocation InternationalGeolocateType - AdministrativeArea string - Locality string - PostalCode string - Latitude float64 - Longitude float64 - Result *Result + Country string + Search string + AddressID string + MaxResults int + Locality string + PostalCode string + Result *Result } func (l Lookup) populate(query url.Values) { l.populateCountry(query) l.populateSearch(query) l.populateMaxResults(query) - l.populateDistance(query) - l.populateGeolocation(query) - l.populateAdministrativeArea(query) l.populateLocality(query) l.populatePostalCode(query) - l.populateLatitude(query) - l.populateLongitude(query) } func (l Lookup) populateCountry(query url.Values) { if len(l.Country) > 0 { @@ -54,25 +44,6 @@ func (l Lookup) populateMaxResults(query url.Values) { } query.Set("max_results", strconv.Itoa(maxResults)) } -func (l Lookup) populateDistance(query url.Values) { - distance := l.Distance - if distance < 1 { - distance = distanceDefault - } - query.Set("distance", strconv.Itoa(distance)) -} -func (l Lookup) populateGeolocation(query url.Values) { - if l.Geolocation != None { - query.Set("geolocation", string(l.Geolocation)) - } else { - query.Del("geolocation") - } -} -func (l Lookup) populateAdministrativeArea(query url.Values) { - if len(l.AdministrativeArea) > 0 { - query.Set("include_only_administrative_area", l.AdministrativeArea) - } -} func (l Lookup) populateLocality(query url.Values) { if len(l.Locality) > 0 { query.Set("include_only_locality", l.Locality) @@ -83,23 +54,3 @@ func (l Lookup) populatePostalCode(query url.Values) { query.Set("include_only_postal_code", l.PostalCode) } } -func (l Lookup) populateLatitude(query url.Values) { - if math.Floor(l.Latitude) != 0 { - query.Set("latitude", strconv.FormatFloat(l.Latitude, 'f', 8, 64)) - } -} -func (l Lookup) populateLongitude(query url.Values) { - if math.Floor(l.Longitude) != 0 { - query.Set("longitude", strconv.FormatFloat(l.Longitude, 'f', 8, 64)) - } -} - -type InternationalGeolocateType string - -const ( - AdminArea = InternationalGeolocateType("adminarea") - Locality = InternationalGeolocateType("locality") - PostalCode = InternationalGeolocateType("postalcode") - Geocodes = InternationalGeolocateType("geocodes") - None = InternationalGeolocateType("") -) diff --git a/international-autocomplete-api/lookup_test.go b/international-autocomplete-api/lookup_test.go index 8295a4d..a11cbfb 100644 --- a/international-autocomplete-api/lookup_test.go +++ b/international-autocomplete-api/lookup_test.go @@ -30,16 +30,15 @@ func (f *LookupFixture) populate() { func (f *LookupFixture) TestDefaults() { f.populate() - f.So(f.query, should.HaveLength, 2) + f.So(f.query, should.HaveLength, 1) f.So(f.query.Get("max_results"), should.Equal, "5") - f.So(f.query.Get("distance"), should.Equal, "5") } func (f *LookupFixture) TestCountry() { f.lookup.Country = "Hello, World!" f.populate() - f.So(f.query, should.HaveLength, 3) + f.So(f.query, should.HaveLength, 2) f.So(f.query.Get("country"), should.Equal, "Hello, World!") } func (f *LookupFixture) TestSearch() { @@ -47,7 +46,7 @@ func (f *LookupFixture) TestSearch() { f.populate() - f.So(f.query, should.HaveLength, 3) + f.So(f.query, should.HaveLength, 2) f.So(f.query.Get("search"), should.Equal, "Hello, World!") } func (f *LookupFixture) TestMaxResults() { @@ -56,34 +55,12 @@ func (f *LookupFixture) TestMaxResults() { f.So(f.query.Get("max_results"), should.Equal, "7") } -func (f *LookupFixture) TestDistance() { - f.lookup.Distance = 3 - f.populate() - - f.So(f.query.Get("distance"), should.Equal, "3") -} -func (f *LookupFixture) TestGeolocation() { - typeList := []InternationalGeolocateType{AdminArea, Locality, PostalCode, Geocodes, None} - for _, geoLocateType := range typeList { - f.lookup.Geolocation = geoLocateType - f.populate() - f.So(f.query.Get("geolocation"), should.Equal, string(geoLocateType)) - } -} -func (f *LookupFixture) TestAdministrativeArea() { - f.lookup.AdministrativeArea = "Hello, World!" - - f.populate() - - f.So(f.query, should.HaveLength, 3) - f.So(f.query.Get("include_only_administrative_area"), should.Equal, "Hello, World!") -} func (f *LookupFixture) TestLocality() { f.lookup.Locality = "Hello, World!" f.populate() - f.So(f.query, should.HaveLength, 3) + f.So(f.query, should.HaveLength, 2) f.So(f.query.Get("include_only_locality"), should.Equal, "Hello, World!") } func (f *LookupFixture) TestPostalCode() { @@ -91,20 +68,6 @@ func (f *LookupFixture) TestPostalCode() { f.populate() - f.So(f.query, should.HaveLength, 3) + f.So(f.query, should.HaveLength, 2) f.So(f.query.Get("include_only_postal_code"), should.Equal, "Hello, World!") } -func (f *LookupFixture) TestLatitude() { - f.lookup.Latitude = 123.458757987986 - - f.populate() - - f.So(f.query.Get("latitude"), should.Equal, "123.45875799") // Here we only care about 8 digits of accuracy -} -func (f *LookupFixture) TestLongitude() { - f.lookup.Longitude = -134.877532234 - - f.populate() - - f.So(f.query.Get("longitude"), should.Equal, "-134.87753223") // Here we only care about 8 digits of accuracy -} diff --git a/wireup/builder.go b/wireup/builder.go index cd54364..4ffc4cf 100644 --- a/wireup/builder.go +++ b/wireup/builder.go @@ -229,7 +229,7 @@ func (b *clientBuilder) buildTransport() *http.Transport { var ( defaultBaseURL_InternationalStreetAPI = &url.URL{Scheme: "https", Host: "international-street.api.smarty.com"} - defaultBaseURL_InternationalAutocompleteAPI = &url.URL{Scheme: "https", Host: "international-autocomplete.api.smarty.com"} + defaultBaseURL_InternationalAutocompleteAPI = &url.URL{Scheme: "https", Host: "international-autocomplete.api.smarty.com/v2"} defaultBaseURL_USStreetAPI = &url.URL{Scheme: "https", Host: "us-street.api.smarty.com"} defaultBaseURL_USZIPCodeAPI = &url.URL{Scheme: "https", Host: "us-zipcode.api.smarty.com"} defaultBaseURL_USAutocompleteAPI = &url.URL{Scheme: "https", Host: "us-autocomplete.api.smarty.com"}