diff --git a/README.md b/README.md index 98cced0..5b24d82 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,37 @@ func main() { } ``` +Sample usage of the Geocoding API with an API key to get an [Address Descriptor](https://developers.google.com/maps/documentation/geocoding/address-descriptors/requests-address-descriptors): + +```go +package main + +import ( + "context" + "log" + + "github.com/kr/pretty" + "googlemaps.github.io/maps" +) + +func main() { + c, err := maps.NewClient(maps.WithAPIKey("Insert-API-Key-Here")) + if err != nil { + log.Fatalf("fatal error: %s", err) + } + r := &maps.GeocodingRequest{ + LatLng: &LatLng{Lat: 40.714224, Lng: -73.961452}, + EnableAddressDescriptor: True + } + reverseGeocodingResponse, _, err := c.ReverseGeocode(context.Background(), r) + if err != nil { + log.Fatalf("fatal error: %s", err) + } + + pretty.Println(reverseGeocodingResponse) +} +``` + ## Features ### Rate limiting diff --git a/addressdescriptor.go b/addressdescriptor.go new file mode 100644 index 0000000..6b4d966 --- /dev/null +++ b/addressdescriptor.go @@ -0,0 +1,148 @@ +// Copyright 2024 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package maps + +import ( + "fmt" +) + +/** +* An enum representing the relationship in space between the landmark and the target. +*/ +type SpatialRelationship string + +const ( + // This is the default relationship when nothing more specific below + // applies. + SPATIAL_RELATIONSHIP_NEAR SpatialRelationship = "NEAR" + // The landmark has a spatial geometry and the target is within its + // bounds. + SPATIAL_RELATIONSHIP_WITHIN SpatialRelationship = "WITHIN" + // The target is directly adjacent to the landmark or landmark's access + // point. + SPATIAL_RELATIONSHIP_BESIDE SpatialRelationship = "BESIDE" + // The target is directly opposite the landmark on the other side of the + // road. + SPATIAL_RELATIONSHIP_ACROSS_THE_ROAD SpatialRelationship = "ACROSS_THE_ROAD" + // On the same route as the landmark but not besides or across. + SPATIAL_RELATIONSHIP_DOWN_THE_ROAD SpatialRelationship = "DOWN_THE_ROAD" + // Not on the same route as the landmark but a single 'turn' away. + SPATIAL_RELATIONSHIP_AROUND_THE_CORNER SpatialRelationship = "AROUND_THE_CORNER" + // Close to the landmark's structure but further away from its access + // point. + SPATIAL_RELATIONSHIP_BEHIND SpatialRelationship = "BEHIND" +) + +// String method for formatted output +func (sr SpatialRelationship) String() string { + return string(sr) +} + +/** +* An enum representing the relationship in space between the area and the target. +*/ +type Containment string + +const ( + /** + * Indicates an unknown containment returned by the server. + */ + CONTAINMENT_UNSPECIFIED Containment = "CONTAINMENT_UNSPECIFIED" + /** The target location is within the area region, close to the center. */ + CONTAINMENT_WITHIN Containment = "WITHIN" + /** The target location is within the area region, close to the edge. */ + CONTAINMENT_OUTSKIRTS Containment = "OUTSKIRTS" + /** The target location is outside the area region, but close by. */ + CONTAINMENT_NEAR Containment = "NEAR" +) + +// String method for formatted output +func (c Containment) String() string { + return string(c) +} + +/** +* Localized variant of a text in a particular language. +*/ +type LocalizedText struct { + // Localized string in the language corresponding to language_code below. + Text string `json:"text"` + // The text's BCP-47 language code, such as "en-US" or "sr-Latn". + // + // For more information, see + // http://www.unicode.org/reports/tr35/#Unicode_locale_identifier. + LanguageCode string `json:"language_code"` +} + +// String method for formatted output +func (lt LocalizedText) String() string { + return fmt.Sprintf("(text=%s, languageCode=%s)", lt.Text, lt.LanguageCode) +} + +// Landmarks that are useful at describing a location. +type Landmark struct { + // The Place ID of the underlying establishment serving as the landmark. + // Can be used to resolve more information about the landmark through Place + // Details or Place Id Lookup. + PlaceID string `json:"place_id"` + // The best name for the landmark. + DisplayName LocalizedText `json:"display_name"` + // One or more values indicating the type of the returned result. Please see Types + // for more detail. + Types []string `json:"types"` + // Defines the spatial relationship between the target location and the + // landmark. + SpatialRelationship SpatialRelationship `json:"spatial_relationship"` + // The straight line distance between the target location and one of the + // landmark's access points. + StraightLineDistanceMeters float32 `json:"straight_line_distance_meters"` + // The travel distance along the road network between the target + // location's closest point on a road, and the landmark's closest access + // point on a road. This can be unpopulated if the landmark is disconnected + // from the part of the road network the target is closest to OR if the + // target location was not actually considered to be on the road network. + TravelDistanceMeters float32 `json:"travel_distance_meters"` +} + +// Precise regions that are useful at describing a location. +type Area struct { + // The Place ID of the underlying area feature. Can be used to + // resolve more information about the area through Place Details or + // Place Id Lookup. + PlaceID string `json:"place_id"` + // The best name for the area. + DisplayName LocalizedText `json:"display_name"` + /** + * An enum representing the relationship in space between the area and the target. + */ + Containment Containment `json:"containment"` +} + +/** + * Represents a descriptor of an address. + * + *

Please see Address + * Descriptors for more detail. + */ +type AddressDescriptor struct { + // A ranked list of nearby landmarks. The most useful (recognizable and + // nearby) landmarks are ranked first. + Landmarks []Landmark `json:"landmarks"` + // A ranked list of containing or adjacent areas. The most useful + // (recognizable and precise) areas are ranked first. + Areas []Area `json:"areas"` +} \ No newline at end of file diff --git a/examples/geocoding/cmdline/main.go b/examples/geocoding/cmdline/main.go index ce71cef..c4753e7 100644 --- a/examples/geocoding/cmdline/main.go +++ b/examples/geocoding/cmdline/main.go @@ -41,6 +41,7 @@ var ( latlng = flag.String("latlng", "", "The textual latitude/longitude value for which you wish to obtain the closest, human-readable address.") resultType = flag.String("result_type", "", "One or more address types, separated by a pipe (|).") locationType = flag.String("location_type", "", "One or more location types, separated by a pipe (|).") + enableAddressDescriptor = flag.String("enable_address_descriptor", "", "True or False. Whether to return the Address Descriptors in the response.") ) func usageAndExit(msg string) { @@ -81,6 +82,7 @@ func main() { parseLatLng(*latlng, r) parseResultType(*resultType, r) parseLocationType(*locationType, r) + parseEnableAddressDescriptor(*enableAddressDescriptor, r) resp, err := client.Geocode(context.Background(), r) check(err) @@ -187,3 +189,11 @@ func parseLocationType(locationType string, r *maps.GeocodingRequest) { } } + +func parseEnableAddressDescriptor(enableAddressDescriptor string, r *maps.GeocodingRequest) { + if enableAddressDescriptor == "True" { + r.EnableAddressDescriptor = true + } else { + r.EnableAddressDescriptor = false + } +} diff --git a/geocoding.go b/geocoding.go index c7785a9..cdf0dd1 100644 --- a/geocoding.go +++ b/geocoding.go @@ -32,9 +32,9 @@ var geocodingAPI = &apiConfig{ } // Geocode makes a Geocoding API request -func (c *Client) Geocode(ctx context.Context, r *GeocodingRequest) ([]GeocodingResult, error) { +func (c *Client) Geocode(ctx context.Context, r *GeocodingRequest) (GeocodingResponse, error) { if r.Address == "" && len(r.Components) == 0 && r.LatLng == nil { - return nil, errors.New("maps: address, components and LatLng are all missing") + return GeocodingResponse{}, errors.New("maps: address, components and LatLng are all missing") } var response struct { @@ -43,38 +43,38 @@ func (c *Client) Geocode(ctx context.Context, r *GeocodingRequest) ([]GeocodingR } if err := c.getJSON(ctx, geocodingAPI, r, &response); err != nil { - return nil, err + return GeocodingResponse{}, err } if err := response.StatusError(); err != nil { - return nil, err + return GeocodingResponse{}, err } - return response.Results, nil + return GeocodingResponse{response.Results, AddressDescriptor{}}, nil } // ReverseGeocode makes a Reverse Geocoding API request -func (c *Client) ReverseGeocode(ctx context.Context, r *GeocodingRequest) ([]GeocodingResult, error) { +func (c *Client) ReverseGeocode(ctx context.Context, r *GeocodingRequest) (GeocodingResponse, error) { // Since Geocode() does not allow a nil LatLng, whereas it is allowed here if r.LatLng == nil && r.PlaceID == "" { - return nil, errors.New("maps: LatLng and PlaceID are both missing") + return GeocodingResponse{}, errors.New("maps: LatLng and PlaceID are both missing") } var response struct { Results []GeocodingResult `json:"results"` + AddressDescriptor AddressDescriptor `json:"address_descriptor"` commonResponse } if err := c.getJSON(ctx, geocodingAPI, r, &response); err != nil { - return nil, err + return GeocodingResponse{}, err } if err := response.StatusError(); err != nil { - return nil, err + return GeocodingResponse{}, err } - return response.Results, nil - + return GeocodingResponse{response.Results, response.AddressDescriptor}, nil } func (r *GeocodingRequest) params() url.Values { @@ -119,6 +119,9 @@ func (r *GeocodingRequest) params() url.Values { if r.Language != "" { q.Set("language", r.Language) } + if r.EnableAddressDescriptor == true { + q.Set("enable_address_descriptor", "true") + } return q } @@ -176,12 +179,23 @@ type GeocodingRequest struct { // Language is the language in which to return results. Optional. Language string + // Language is the language in which to return results. Optional. + EnableAddressDescriptor bool + // Custom allows passing through custom parameters to the Geocoding back end. // Use with caution. For more detail on why this is required, please see // https://googlegeodevelopers.blogspot.com/2016/11/address-geocoding-in-google-maps-apis.html Custom url.Values } +// GeocodingResponse is the response to a Geocoding API request. +type GeocodingResponse struct { + // Results is the Geocoding results + Results []GeocodingResult + // The Address Descriptor for the target in the reverse geocoding requeest + AddressDescriptor AddressDescriptor +} + // GeocodingResult is a single geocoded address type GeocodingResult struct { AddressComponents []AddressComponent `json:"address_components"` diff --git a/geocoding_test.go b/geocoding_test.go index a00e285..56d76f3 100644 --- a/geocoding_test.go +++ b/geocoding_test.go @@ -127,72 +127,76 @@ func TestGeocodingGoogleHQ(t *testing.T) { resp, err := c.Geocode(context.Background(), r) - if len(resp) != 1 { - t.Errorf("Expected length of response is 1, was %+v", len(resp)) + if len(resp.Results) != 1 { + t.Errorf("Expected length of response is 1, was %+v", len(resp.Results)) } if err != nil { t.Errorf("r.Get returned non nil error: %v", err) } - correctResponse := GeocodingResult{ - AddressComponents: []AddressComponent{ + correctResponse := GeocodingResponse{ + Results: []GeocodingResult{ { - LongName: "1600", - ShortName: "1600", - Types: []string{"street_number"}, + AddressComponents: []AddressComponent{ + { + LongName: "1600", + ShortName: "1600", + Types: []string{"street_number"}, + }, + { + LongName: "Amphitheatre Pkwy", + ShortName: "Amphitheatre Pkwy", + Types: []string{"route"}, + }, + { + LongName: "Mountain View", + ShortName: "Mountain View", + Types: []string{"locality", "political"}, + }, + { + LongName: "Santa Clara County", + ShortName: "Santa Clara County", + Types: []string{"administrative_area_level_2", "political"}, + }, + { + LongName: "California", + ShortName: "CA", + Types: []string{"administrative_area_level_1", "political"}, + }, + { + LongName: "United States", + ShortName: "US", + Types: []string{"country", "political"}, + }, + { + LongName: "94043", + ShortName: "94043", + Types: []string{"postal_code"}, + }, + }, + FormattedAddress: "1600 Amphitheatre Parkway, Mountain View, CA 94043, USA", + Geometry: AddressGeometry{ + Location: LatLng{Lat: 37.4224764, Lng: -122.0842499}, + Bounds: LatLngBounds{ + NorthEast: LatLng{Lat: 37.4238253802915, Lng: -122.0829009197085}, + SouthWest: LatLng{Lat: 37.4211274197085, Lng: -122.0855988802915}, + }, + LocationType: "ROOFTOP", + Viewport: LatLngBounds{ + NorthEast: LatLng{Lat: 37.4238253802915, Lng: -122.0829009197085}, + SouthWest: LatLng{Lat: 37.4211274197085, Lng: -122.0855988802915}, + }, + Types: nil, + }, + PartialMatch: false, + PlaceID: "ChIJ2eUgeAK6j4ARbn5u_wAGqWA", + Types: []string{"street_address"}, }, - { - LongName: "Amphitheatre Pkwy", - ShortName: "Amphitheatre Pkwy", - Types: []string{"route"}, - }, - { - LongName: "Mountain View", - ShortName: "Mountain View", - Types: []string{"locality", "political"}, - }, - { - LongName: "Santa Clara County", - ShortName: "Santa Clara County", - Types: []string{"administrative_area_level_2", "political"}, - }, - { - LongName: "California", - ShortName: "CA", - Types: []string{"administrative_area_level_1", "political"}, - }, - { - LongName: "United States", - ShortName: "US", - Types: []string{"country", "political"}, - }, - { - LongName: "94043", - ShortName: "94043", - Types: []string{"postal_code"}, - }, - }, - FormattedAddress: "1600 Amphitheatre Parkway, Mountain View, CA 94043, USA", - Geometry: AddressGeometry{ - Location: LatLng{Lat: 37.4224764, Lng: -122.0842499}, - Bounds: LatLngBounds{ - NorthEast: LatLng{Lat: 37.4238253802915, Lng: -122.0829009197085}, - SouthWest: LatLng{Lat: 37.4211274197085, Lng: -122.0855988802915}, - }, - LocationType: "ROOFTOP", - Viewport: LatLngBounds{ - NorthEast: LatLng{Lat: 37.4238253802915, Lng: -122.0829009197085}, - SouthWest: LatLng{Lat: 37.4211274197085, Lng: -122.0855988802915}, - }, - Types: nil, }, - PartialMatch: false, - PlaceID: "ChIJ2eUgeAK6j4ARbn5u_wAGqWA", - Types: []string{"street_address"}, } - if !reflect.DeepEqual(resp[0], correctResponse) { - t.Errorf("expected %+v, was %+v", correctResponse, resp[0]) + if !reflect.DeepEqual(resp, correctResponse) { + t.Errorf("expected %+v, was %+v", correctResponse, resp) } } @@ -310,76 +314,80 @@ func TestGeocodingReverseGeocoding(t *testing.T) { resp, err := c.ReverseGeocode(context.Background(), r) - if len(resp) != 1 { - t.Errorf("expected %+v, was %+v", 1, len(resp)) + if len(resp.Results) != 1 { + t.Errorf("expected %+v, was %+v", 1, len(resp.Results)) } if err != nil { t.Errorf("r.Get returned non nil error: %v", err) } - correctResponse := GeocodingResult{ - AddressComponents: []AddressComponent{ - { - LongName: "277", - ShortName: "277", - Types: []string{"street_number"}, - }, + correctResponse := GeocodingResponse{ + Results: []GeocodingResult{ { - LongName: "Bedford Avenue", - ShortName: "Bedford Ave", - Types: []string{"route"}, - }, - { - LongName: "Williamsburg", - ShortName: "Williamsburg", - Types: []string{"neighborhood", "political"}, - }, - { - LongName: "Brooklyn", - ShortName: "Brooklyn", - Types: []string{"sublocality", "political"}, - }, - { - LongName: "Kings", - ShortName: "Kings", - Types: []string{"administrative_area_level_2", "political"}, - }, - { - LongName: "New York", - ShortName: "NY", - Types: []string{"administrative_area_level_1", "political"}, - }, - { - LongName: "United States", - ShortName: "US", - Types: []string{"country", "political"}, - }, - { - LongName: "11211", - ShortName: "11211", - Types: []string{"postal_code"}, + AddressComponents: []AddressComponent{ + { + LongName: "277", + ShortName: "277", + Types: []string{"street_number"}, + }, + { + LongName: "Bedford Avenue", + ShortName: "Bedford Ave", + Types: []string{"route"}, + }, + { + LongName: "Williamsburg", + ShortName: "Williamsburg", + Types: []string{"neighborhood", "political"}, + }, + { + LongName: "Brooklyn", + ShortName: "Brooklyn", + Types: []string{"sublocality", "political"}, + }, + { + LongName: "Kings", + ShortName: "Kings", + Types: []string{"administrative_area_level_2", "political"}, + }, + { + LongName: "New York", + ShortName: "NY", + Types: []string{"administrative_area_level_1", "political"}, + }, + { + LongName: "United States", + ShortName: "US", + Types: []string{"country", "political"}, + }, + { + LongName: "11211", + ShortName: "11211", + Types: []string{"postal_code"}, + }, + }, + FormattedAddress: "277 Bedford Avenue, Brooklyn, NY 11211, USA", + Geometry: AddressGeometry{ + Location: LatLng{Lat: 40.714232, Lng: -73.9612889}, + Bounds: LatLngBounds{ + NorthEast: LatLng{Lat: 40.7155809802915, Lng: -73.9599399197085}, + SouthWest: LatLng{Lat: 40.7128830197085, Lng: -73.96263788029151}, + }, + LocationType: "ROOFTOP", + Viewport: LatLngBounds{ + NorthEast: LatLng{Lat: 40.7155809802915, Lng: -73.9599399197085}, + SouthWest: LatLng{Lat: 40.7128830197085, Lng: -73.96263788029151}, + }, + Types: nil, + }, + PlaceID: "ChIJd8BlQ2BZwokRAFUEcm_qrcA", + Types: []string{"street_address"}, }, }, - FormattedAddress: "277 Bedford Avenue, Brooklyn, NY 11211, USA", - Geometry: AddressGeometry{ - Location: LatLng{Lat: 40.714232, Lng: -73.9612889}, - Bounds: LatLngBounds{ - NorthEast: LatLng{Lat: 40.7155809802915, Lng: -73.9599399197085}, - SouthWest: LatLng{Lat: 40.7128830197085, Lng: -73.96263788029151}, - }, - LocationType: "ROOFTOP", - Viewport: LatLngBounds{ - NorthEast: LatLng{Lat: 40.7155809802915, Lng: -73.9599399197085}, - SouthWest: LatLng{Lat: 40.7128830197085, Lng: -73.96263788029151}, - }, - Types: nil, - }, - PlaceID: "ChIJd8BlQ2BZwokRAFUEcm_qrcA", - Types: []string{"street_address"}, } - if !reflect.DeepEqual(resp[0], correctResponse) { - t.Errorf("expected %+v, was %+v", correctResponse, resp[0]) + if !reflect.DeepEqual(resp, correctResponse) { + t.Errorf("expected %+v, was %+v", correctResponse, resp) } } @@ -528,6 +536,99 @@ func TestReverseGeocodingPlaceID(t *testing.T) { ] } ], + "address_descriptor": { + "landmarks": [ + { + "place_id": "ChIJvUbrwCCoAWARX2QiHCsn5A4", + "display_name": { + "text": "Kinkaku-ji", + "language_code": "en" + }, + "types": [ + "establishment", + "place_of_worship", + "point_of_interest", + "tourist_attraction" + ], + "spatial_relationship": "NEAR", + "straight_line_distance_meters": 0.009104185 + }, + { + "place_id": "ChIJf2s61SCoAWARVtK8cnSu6zw", + "display_name": { + "text": "Shariden Kinkaku", + "language_code": "en" + }, + "types": [ + "establishment", + "place_of_worship", + "point_of_interest", + "tourist_attraction" + ], + "spatial_relationship": "WITHIN", + "straight_line_distance_meters": 73.58092 + }, + { + "place_id": "ChIJXZeF2jipAWARNbF8pJDRjFc", + "display_name": { + "text": "Kyōko-chi Pond", + "language_code": "en" + }, + "types": [ + "establishment", + "park", + "point_of_interest" + ], + "spatial_relationship": "BEHIND", + "straight_line_distance_meters": 57.99922 + }, + { + "place_id": "ChIJj69vLCapAWAR0FBBPEfPeAQ", + "display_name": { + "text": "鹿苑寺(金閣寺)", + "language_code": "ja" + }, + "types": [ + "establishment", + "place_of_worship", + "point_of_interest" + ], + "spatial_relationship": "WITHIN", + "straight_line_distance_meters": 32.30453 + }, + { + "place_id": "ChIJ482HblCpAWARoLBXDZpv7aI", + "display_name": { + "text": "Kinkaku-ji Fence", + "language_code": "en" + }, + "types": [ + "establishment", + "point_of_interest" + ], + "spatial_relationship": "WITHIN", + "straight_line_distance_meters": 99.38629 + } + ], + "areas": [ + { + "place_id": "ChIJe9XMwiCoAWARVrQpOsYqdBE", + "display_name": { + "text": "Kinkakujicho", + "language_code": "en" + }, + "containment" : "WITHIN" + }, + { + "place_id": "ChIJk-6T5COoAWARa-KMWGWzrwQ", + "display_name": { + "text": "Kinkaku-ji", + "language_code": "en" + }, + "containment" : "OUTSKIRTS" + } + ] + }, "status": "OK" }` @@ -539,67 +640,122 @@ func TestReverseGeocodingPlaceID(t *testing.T) { } resp, err := c.ReverseGeocode(context.Background(), r) - if len(resp) != 1 { - t.Errorf("Expected length of response is 1, was %+v", len(resp)) + if len(resp.Results) != 1 { + t.Errorf("Expected length of response is 1, was %+v", len(resp.Results)) } if err != nil { t.Errorf("r.Get returned non nil error: %v", err) } - correctResponse := GeocodingResult{ - AddressComponents: []AddressComponent{ - { - LongName: "1600", - ShortName: "1600", - Types: []string{"street_number"}, - }, - { - LongName: "Amphitheatre Pkwy", - ShortName: "Amphitheatre Pkwy", - Types: []string{"route"}, - }, - { - LongName: "Mountain View", - ShortName: "Mountain View", - Types: []string{"locality", "political"}, - }, + correctResponse := GeocodingResponse{ + Results: []GeocodingResult{ { - LongName: "Santa Clara County", - ShortName: "Santa Clara County", - Types: []string{"administrative_area_level_2", "political"}, - }, - { - LongName: "California", - ShortName: "CA", - Types: []string{"administrative_area_level_1", "political"}, - }, - { - LongName: "United States", - ShortName: "US", - Types: []string{"country", "political"}, - }, - { - LongName: "94043", - ShortName: "94043", - Types: []string{"postal_code"}, + AddressComponents: []AddressComponent{ + { + LongName: "1600", + ShortName: "1600", + Types: []string{"street_number"}, + }, + { + LongName: "Amphitheatre Pkwy", + ShortName: "Amphitheatre Pkwy", + Types: []string{"route"}, + }, + { + LongName: "Mountain View", + ShortName: "Mountain View", + Types: []string{"locality", "political"}, + }, + { + LongName: "Santa Clara County", + ShortName: "Santa Clara County", + Types: []string{"administrative_area_level_2", "political"}, + }, + { + LongName: "California", + ShortName: "CA", + Types: []string{"administrative_area_level_1", "political"}, + }, + { + LongName: "United States", + ShortName: "US", + Types: []string{"country", "political"}, + }, + { + LongName: "94043", + ShortName: "94043", + Types: []string{"postal_code"}, + }, + }, + FormattedAddress: "1600 Amphitheatre Parkway, Mountain View, CA 94043, USA", + Geometry: AddressGeometry{ + Location: LatLng{Lat: 37.4224764, Lng: -122.0842499}, + LocationType: "ROOFTOP", + Viewport: LatLngBounds{ + NorthEast: LatLng{Lat: 37.4238253802915, Lng: -122.0829009197085}, + SouthWest: LatLng{Lat: 37.4211274197085, Lng: -122.0855988802915}, + }, + Types: nil, + }, + PlaceID: "ChIJ2eUgeAK6j4ARbn5u_wAGqWA", + Types: []string{"street_address"}, }, }, - FormattedAddress: "1600 Amphitheatre Parkway, Mountain View, CA 94043, USA", - Geometry: AddressGeometry{ - Location: LatLng{Lat: 37.4224764, Lng: -122.0842499}, - LocationType: "ROOFTOP", - Viewport: LatLngBounds{ - NorthEast: LatLng{Lat: 37.4238253802915, Lng: -122.0829009197085}, - SouthWest: LatLng{Lat: 37.4211274197085, Lng: -122.0855988802915}, + AddressDescriptor: AddressDescriptor{ + Landmarks: []Landmark{ + { + PlaceID: "ChIJvUbrwCCoAWARX2QiHCsn5A4", + DisplayName: LocalizedText{Text: "Kinkaku-ji", LanguageCode: "en"}, + Types: []string{"establishment", "place_of_worship", "point_of_interest", "tourist_attraction"}, + SpatialRelationship: SPATIAL_RELATIONSHIP_NEAR, + StraightLineDistanceMeters: 0.009104185, + }, + { + PlaceID: "ChIJf2s61SCoAWARVtK8cnSu6zw", + DisplayName: LocalizedText{Text: "Shariden Kinkaku", LanguageCode: "en"}, + Types: []string{"establishment", "place_of_worship", "point_of_interest", "tourist_attraction"}, + SpatialRelationship: SPATIAL_RELATIONSHIP_WITHIN, + StraightLineDistanceMeters: 73.58092, + }, + { + PlaceID: "ChIJXZeF2jipAWARNbF8pJDRjFc", + DisplayName: LocalizedText{Text: "Kyōko-chi Pond", LanguageCode: "en"}, + Types: []string{"establishment", "park", "point_of_interest"}, + SpatialRelationship: SPATIAL_RELATIONSHIP_BEHIND, + StraightLineDistanceMeters: 57.99922, + }, + { + PlaceID: "ChIJj69vLCapAWAR0FBBPEfPeAQ", + DisplayName: LocalizedText{Text: "鹿苑寺(金閣寺)", LanguageCode: "ja"}, + Types: []string{"establishment", "place_of_worship", "point_of_interest"}, + SpatialRelationship: SPATIAL_RELATIONSHIP_WITHIN, + StraightLineDistanceMeters: 32.30453, + }, + { + PlaceID: "ChIJ482HblCpAWARoLBXDZpv7aI", + DisplayName: LocalizedText{Text: "Kinkaku-ji Fence", LanguageCode: "en"}, + Types: []string{"establishment", "point_of_interest"}, + SpatialRelationship: SPATIAL_RELATIONSHIP_WITHIN, + StraightLineDistanceMeters: 99.38629, + }, + }, + Areas: []Area{ + { + PlaceID: "ChIJe9XMwiCoAWARVrQpOsYqdBE", + DisplayName: LocalizedText{Text: "Kinkakujicho", LanguageCode: "en"}, + Containment: CONTAINMENT_WITHIN, + }, + { + PlaceID: "ChIJk-6T5COoAWARa-KMWGWzrwQ", + DisplayName: LocalizedText{Text: "Kinkaku-ji", LanguageCode: "en"}, + Containment: CONTAINMENT_OUTSKIRTS, + }, }, - Types: nil, }, - PlaceID: "ChIJ2eUgeAK6j4ARbn5u_wAGqWA", - Types: []string{"street_address"}, } - if !reflect.DeepEqual(resp[0], correctResponse) { - t.Errorf("expected %+v, was %+v", correctResponse, resp[0]) + if !reflect.DeepEqual(resp, correctResponse) { + t.Errorf("expected %+v, was %+v", correctResponse, resp) } } @@ -641,11 +797,11 @@ func TestGeocodingZeroResults(t *testing.T) { t.Errorf("Unexpected error for ZERO_RESULTS status") } - if response == nil { + if response.Results == nil { t.Errorf("Unexpected nil response for ZERO_RESULTS status") } - if len(response) != 0 { + if len(response.Results) != 0 { t.Errorf("Unexpected response for ZERO_RESULTS status") } } @@ -664,11 +820,11 @@ func TestReverseGeocodingZeroResults(t *testing.T) { t.Errorf("Unexpected error for ZERO_RESULTS status") } - if response == nil { + if response.Results == nil { t.Errorf("Unexpected nil response for ZERO_RESULTS status") } - if len(response) != 0 { + if len(response.Results) != 0 { t.Errorf("Unexpected response for ZERO_RESULTS status") } }