I am using google autocomplete address api, it returns all the required data but not postal code. Any idea how to get postal code in api response. Below is the my url and api response returned by this api.
https://maps.googleapis.com/maps/api/place/autocomplete/json?input=19becket st &types=address&key=my_api_key
data return is in following format
{
"description": "19 Becket St, Boston, MA, USA",
"matched_substrings": [
{
"length": 2,
"offset": 0
},
{
"length": 9,
"offset": 3
}
],
"place_id": "ChIJN9v2H4l744kRRg9DI6ctGhY",
"reference": "ChIJN9v2H4l744kRRg9DI6ctGhY",
"structured_formatting": {
"main_text": "19 Becket St",
"main_text_matched_substrings": [
{
"length": 2,
"offset": 0
},
{
"length": 9,
"offset": 3
}
],
"secondary_text": "Boston, MA, USA"
},
"terms": [
{
"offset": 0,
"value": "19"
},
{
"offset": 3,
"value": "Becket St"
},
{
"offset": 14,
"value": "Boston"
},
{
"offset": 22,
"value": "MA"
},
{
"offset": 26,
"value": "USA"
}
],
"types": [
"premise",
"geocode"
]
},
Use the place_id to do a followup request for place details.
Use the same session token for both the autocomplete requests and details requests
Use the fields parameter in the details requests
https://maps.googleapis.com/maps/api/place/details/json
?fields=address_components
&place_id=ChIJN9v2H4l744kRRg9DI6ctGhY
&key=YOUR_API_KEY
The zip code will be in the address_components field of the response with type postal_code similar to the following:
{
address_components":
[
{ "long_name": "48", "short_name": "48", "types": ["street_number"] },
{
"long_name": "Pirrama Road",
"short_name": "Pirrama Rd",
"types": ["route"],
},
{
"long_name": "Pyrmont",
"short_name": "Pyrmont",
"types": ["locality", "political"],
},
{
"long_name": "Council of the City of Sydney",
"short_name": "Sydney",
"types": ["administrative_area_level_2", "political"],
},
{
"long_name": "New South Wales",
"short_name": "NSW",
"types": ["administrative_area_level_1", "political"],
},
{
"long_name": "Australia",
"short_name": "AU",
"types": ["country", "political"],
},
{
"long_name": "2009",
"short_name": "2009",
"types": ["postal_code"],
},
],
}
Related
I'm using the Google Places API to find the address details of a small village in India, following this documentation from Google. My https request looks as follows:
https://maps.googleapis.com/maps/api/place/findplacefromtext/json?key=MY_API_KEY&inputtype=textquery&input=Dahigaon&fields=name,geometry,address_component
My problem is that the request above returns the following error:
Error while parsing 'fields' parameter: Unsupported field name 'address_component'.
I've tried a couple of other 'field' values, and they all seem to work except for address_component. Any thoughts on what I'm doing wrong?
Figured this one out. Apparently "Place Search, Nearby Search, and Text Search requests all return a subset of the fields that are returned by Place Details requests." See here for details: LINK
address_component is one of the fields that is not supported ...
I went through the same thing a while ago, basically you should make 2 calls, the first one to:
curl --request GET \
--url 'https://maps.googleapis.com/maps/api/place/findplacefromtext/json?input=360%20Lobelia%20Rd&inputtype=textquery&key=YOUR_KEY'
this will return the following.
{
"candidates": [
{
"place_id": "ChIJCesBrxmd5ogR5kyZiY35HLI"
}
],
"status": "OK"
}
you should take the place_id and use it in a second call like this:
curl --request GET \
--url 'https://maps.googleapis.com/maps/api/place/details/json?place_id=ChIJCesBrxmd5ogR5kyZiY35HLI&key=YOUR_KEY'
this will return the following.
{
"html_attributions": [],
"result": {
"address_components": [
{
"long_name": "360",
"short_name": "360",
"types": [
"street_number"
]
},
{
"long_name": "Lobelia Road",
"short_name": "Lobelia Rd",
"types": [
"route"
]
},
{
"long_name": "St. Augustine",
"short_name": "St. Augustine",
"types": [
"locality",
"political"
]
},
{
"long_name": "St. Johns County",
"short_name": "St Johns County",
"types": [
"administrative_area_level_2",
"political"
]
},
{
"long_name": "Florida",
"short_name": "FL",
"types": [
"administrative_area_level_1",
"political"
]
},
{
"long_name": "United States",
"short_name": "US",
"types": [
"country",
"political"
]
},
{
"long_name": "32086",
"short_name": "32086",
"types": [
"postal_code"
]
},
{
"long_name": "6516",
"short_name": "6516",
"types": [
"postal_code_suffix"
]
}
],
"adr_address": "<span class=\"street-address\">360 Lobelia Rd</span>, <span class=\"locality\">St. Augustine</span>, <span class=\"region\">FL</span> <span class=\"postal-code\">32086-6516</span>, <span class=\"country-name\">USA</span>",
"formatted_address": "360 Lobelia Rd, St. Augustine, FL 32086, USA",
"geometry": {
"location": {
"lat": 29.8358907,
"lng": -81.31464799999999
},
"viewport": {
"northeast": {
"lat": 29.8372717802915,
"lng": -81.31318596970848
},
"southwest": {
"lat": 29.8345738197085,
"lng": -81.31588393029149
}
}
},
"icon": "https://maps.gstatic.com/mapfiles/place_api/icons/v1/png_71/geocode-71.png",
"icon_background_color": "#7B9EB0",
"icon_mask_base_uri": "https://maps.gstatic.com/mapfiles/place_api/icons/v2/generic_pinlet",
"name": "360 Lobelia Rd",
"place_id": "ChIJCesBrxmd5ogR5kyZiY35HLI",
"reference": "ChIJCesBrxmd5ogR5kyZiY35HLI",
"types": [
"premise"
],
"url": "https://maps.google.com/?q=360+Lobelia+Rd,+St.+Augustine,+FL+32086,+USA&ftid=0x88e69d19af01eb09:0xb21cf98d89994ce6",
"utc_offset": -240,
"vicinity": "St. Augustine"
},
"status": "OK"
}
I don't know why the other way in the documentation, I imagine that at some point due to billing issues they have separated it into 2 calls.
From what I understood about billing, for every 1000 addresses searched in this way, you would be spending approximately 34 USD.
I have a large JSON object returned from a Google Maps reverse geocode lookup.
in this object there are many possible location details returned.
Using jq how do I select the first returned location with a location_type "ROOFTOP" and get the formatted_address and place_id ?
in the below example the first entry has a location_type of "GEOMETRIC_CENTER"
The second entry has the "ROOFTOP" location_type. I want to ignore the entry with "GEOMETRIC_CENTER" and only return the fist entry with location_type "ROOFTOP"
Many thanks
Mike
[
{
"address_components": [
{
"long_name": "30",
"short_name": "30",
"types": [
"street_number"
]
},
{
"long_name": "Allée Jean de Lattre de Tassigny",
"short_name": "Allée Jean de Lattre de Tassigny",
"types": [
"route"
]
},
{
"long_name": "Montpellier",
"short_name": "Montpellier",
"types": [
"locality",
"political"
]
},
{
"long_name": "Hérault",
"short_name": "Hérault",
"types": [
"administrative_area_level_2",
"political"
]
},
{
"long_name": "Occitanie",
"short_name": "Occitanie",
"types": [
"administrative_area_level_1",
"political"
]
},
{
"long_name": "France",
"short_name": "FR",
"types": [
"country",
"political"
]
},
{
"long_name": "34000",
"short_name": "34000",
"types": [
"postal_code"
]
}
],
"formatted_address": "30 Allée Jean de Lattre de Tassigny, 34000 Montpellier, France",
"geometry": {
"bounds": {
"northeast": {
"lat": 43.6097932,
"lng": 3.8817559
},
"southwest": {
"lat": 43.6094097,
"lng": 3.881321299999999
}
},
"location": {
"lat": 43.6095516,
"lng": 3.881559199999999
},
"location_type": "GEOMETRIC_CENTER",
"viewport": {
"northeast": {
"lat": 43.6109504302915,
"lng": 3.882887580291503
},
"southwest": {
"lat": 43.6082524697085,
"lng": 3.880189619708498
}
}
},
"place_id": "ChIJ13k0paCvthIRcTgwBrisc10",
"types": [
"premise"
]
},
{
"address_components": [
{
"long_name": "8",
"short_name": "8",
"types": [
"street_number"
]
},
{
"long_name": "Rue Michelet",
"short_name": "Rue Michelet",
"types": [
"route"
]
},
{
"long_name": "Montpellier",
"short_name": "Montpellier",
"types": [
"locality",
"political"
]
},
{
"long_name": "Hérault",
"short_name": "Hérault",
"types": [
"administrative_area_level_2",
"political"
]
},
{
"long_name": "Occitanie",
"short_name": "Occitanie",
"types": [
"administrative_area_level_1",
"political"
]
},
{
"long_name": "France",
"short_name": "FR",
"types": [
"country",
"political"
]
},
{
"long_name": "34000",
"short_name": "34000",
"types": [
"postal_code"
]
}
],
"formatted_address": "8 Rue Michelet, 34000 Montpellier, France",
"geometry": {
"location": {
"lat": 43.60911189999999,
"lng": 3.8814264
},
"location_type": "ROOFTOP",
"viewport": {
"northeast": {
"lat": 43.61046088029149,
"lng": 3.882775380291502
},
"southwest": {
"lat": 43.60776291970849,
"lng": 3.880077419708498
}
}
},
"place_id": "ChIJ2UaGt6CvthIRJoNW7vS2Ibs",
"plus_code": {
"compound_code": "JV5J+JH Montpellier, France",
"global_code": "8FM5JV5J+JH"
},
"types": [
"street_address"
]
}
]
Rather than using .[0] to obtain the first object satisfying, it would be more efficient to use first/1. Here is a solution using first/1 and ..:
$ jq 'first(..|objects|select(.geometry.location_type == "ROOFTOP"))
| {formatted_address, place_id}' input.json
{
"formatted_address": "8 Rue Michelet, 34000 Montpellier, France",
"place_id": "ChIJ2UaGt6CvthIRJoNW7vS2Ibs"
}
Using firstin this way avoids having to compute the entire array before taking the first element.
Alternatively ...
Retrieving the first top-level object, without using ..:
first(.[] | select(.geometry.location_type=="ROOFTOP"))
Assuming the entries are enclosed in an array, you can use this jq filter that gives all objects having ROOFTOP as location:
jq '.[] | select(.geometry.location_type=="ROOFTOP")' file
If you want to select only the first one from all objects, use the following:
jq 'map(select(.geometry.location_type=="ROOFTOP"))|.[0]' file
And you only need need some of the values, pipe it another filter like this:
jq 'map(select(.geometry.location_type=="ROOFTOP"))|.[0]|.place_id, .formatted_address' file
I'm trying to write a unit test for getAddress() a function that gets the address from a google.maps.places.autocomplete. To trigger the function I need to set a new place programmatically because the place_changed event handler calls getAddress(). When setting a place using the GUI location.lat is a function and when doing programmatically it is a property.
So to set a new place I do this:
let place = { "address_components": [{ "long_name": "Auckland", "short_name": "Auckland", "types": ["locality", "political"] }, { "long_name": "Auckland", "short_name": "Auckland", "types": ["administrative_area_level_2", "political"] }, { "long_name": "Auckland", "short_name": "Auckland", "types": ["administrative_area_level_1", "political"] }, { "long_name": "New Zealand", "short_name": "NZ", "types": ["country", "political"] }], "adr_address": "<span class=\"locality\">Auckland</span>, <span class=\"country-name\">New Zealand</span>", "formatted_address": "Auckland, New Zealand", "geometry": { "location": { "lat": -36.8484597, "lng": 174.76333150000005 }, "viewport": { "south": -37.0654751, "west": 174.44380160000003, "north": -36.660571, "east": 175.2871371 } }, "icon": "https://maps.gstatic.com/mapfiles/place_api/icons/geocode-71.png", "id": "088418ddc17fef2513462d92dbee1355929b35ed", "name": "Auckland", "photos": [{ "height": 1836, "html_attributions": ["Johannes De Smedt"], "width": 3264 }, { "height": 2988, "html_attributions": ["Michal Panek"], "width": 5312 }, { "height": 3096, "html_attributions": ["Sakchhyam Malla"], "width": 4128 }, { "height": 3672, "html_attributions": ["Maria Bitunjac"], "width": 4896 }, { "height": 1836, "html_attributions": ["Carol Prichard"], "width": 3264 }, { "height": 3120, "html_attributions": ["Kovács György"], "width": 4208 }, { "height": 1504, "html_attributions": ["Martin Mobers"], "width": 2006 }, { "height": 492, "html_attributions": ["Priyesh Bhavsar"], "width": 1000 }, { "height": 2988, "html_attributions": ["Alvie Granito"], "width": 5312 }, { "height": 3265, "html_attributions": ["Simon Chen"], "width": 4898 }], "place_id": "ChIJ--acWvtHDW0RF5miQ2HvAAU", "reference": "CmRbAAAAEJGwhQ0l3O1QapXvbJ_s-xNVyh7UxBjd89D9Q860dfhb5Xh3xeY95UT1tIdugiTRhhZHT2qk_wzUqfd3wPS-vdX1pBljxcPtMUqhTtslzMyVccViA9ckk50Xv_cFWNXFEhCPkvW84Okrk2SJUpUDLGz8GhSEN1dm_0tJj4nEHYo0-bkRdOykYQ", "scope": "GOOGLE", "types": ["locality", "political"], "url": "https://maps.google.com/?q=Auckland,+New+Zealand&ftid=0x6d0d47fb5a9ce6fb:0x500ef6143a29917", "utc_offset": 780, "vicinity": "Auckland" }
testHost.areaPicker.autocomplete.set("place", place);
regarding my place variable I get this compile time error:
'"adr_address"' does not exist in type 'PlaceResult'.
However when I do this, for some reason the resulting place object's geometry.lat and geometry.lng are no longer functions but now they are properties.
But when I use the autocomplete in real scenarios they are functions. As they should be. How do I get them to be functions in my unit test? Full code below.
Unit test:
it('EmitAreaChanged_AreaEntered_AreaPlaceValueMakesItToHost', () => {
let place = { "address_components": [{ "long_name": "Auckland", "short_name": "Auckland", "types": ["locality", "political"] }, { "long_name": "Auckland", "short_name": "Auckland", "types": ["administrative_area_level_2", "political"] }, { "long_name": "Auckland", "short_name": "Auckland", "types": ["administrative_area_level_1", "political"] }, { "long_name": "New Zealand", "short_name": "NZ", "types": ["country", "political"] }], "adr_address": "<span class=\"locality\">Auckland</span>, <span class=\"country-name\">New Zealand</span>", "formatted_address": "Auckland, New Zealand", "geometry": { "location": { "lat": -36.8484597, "lng": 174.76333150000005 }, "viewport": { "south": -37.0654751, "west": 174.44380160000003, "north": -36.660571, "east": 175.2871371 } }, "icon": "https://maps.gstatic.com/mapfiles/place_api/icons/geocode-71.png", "id": "088418ddc17fef2513462d92dbee1355929b35ed", "name": "Auckland", "photos": [{ "height": 1836, "html_attributions": ["Johannes De Smedt"], "width": 3264 }, { "height": 2988, "html_attributions": ["Michal Panek"], "width": 5312 }, { "height": 3096, "html_attributions": ["Sakchhyam Malla"], "width": 4128 }, { "height": 3672, "html_attributions": ["Maria Bitunjac"], "width": 4896 }, { "height": 1836, "html_attributions": ["Carol Prichard"], "width": 3264 }, { "height": 3120, "html_attributions": ["Kovács György"], "width": 4208 }, { "height": 1504, "html_attributions": ["Martin Mobers"], "width": 2006 }, { "height": 492, "html_attributions": ["Priyesh Bhavsar"], "width": 1000 }, { "height": 2988, "html_attributions": ["Alvie Granito"], "width": 5312 }, { "height": 3265, "html_attributions": ["Simon Chen"], "width": 4898 }], "place_id": "ChIJ--acWvtHDW0RF5miQ2HvAAU", "reference": "CmRbAAAAEJGwhQ0l3O1QapXvbJ_s-xNVyh7UxBjd89D9Q860dfhb5Xh3xeY95UT1tIdugiTRhhZHT2qk_wzUqfd3wPS-vdX1pBljxcPtMUqhTtslzMyVccViA9ckk50Xv_cFWNXFEhCPkvW84Okrk2SJUpUDLGz8GhSEN1dm_0tJj4nEHYo0-bkRdOykYQ", "scope": "GOOGLE", "types": ["locality", "political"], "url": "https://maps.google.com/?q=Auckland,+New+Zealand&ftid=0x6d0d47fb5a9ce6fb:0x500ef6143a29917", "utc_offset": 780, "vicinity": "Auckland" }
testHost.areaPicker.autocomplete.set("place", place);
expect(testHost.placeValue).toBe(true);
});
relevant part of my component under test that uses a google autocomplete:
ngAfterViewInit() {
this.autocomplete = new google.maps.places.Autocomplete(
<HTMLInputElement>this.areaInput.nativeElement, this._options);
this.autocomplete.addListener('place_changed', () => {
this.getAddress(this.autocomplete)
});
this.areaInput.nativeElement.setCustomValidity("");
}
public getAddress(autocomplete: google.maps.places.Autocomplete): void {
if (this._canGetAddress) {
var place: google.maps.places.PlaceResult = autocomplete.getPlace();
this.address = place['formatted_address'];
var location = place['geometry']['location'];
var lat = location.lat();
var lng = location.lng();
this.onAreaChanged.emit({areaEntered: true, place: place});
this.areaInput.nativeElement.setCustomValidity("");
}
}
Here is my code I want to test:
public getAddress(autocomplete: google.maps.places.Autocomplete): void {
if (this._canGetAddress) {
var place: google.maps.places.PlaceResult = autocomplete.getPlace();
this.address = place['formatted_address'];
var location = place['geometry']['location'];
var lat = location.lat();
var lng = location.lng();
this.onAreaChanged.emit({areaEntered: true, place: place});
this.areaInput.nativeElement.setCustomValidity("");
}
}
The location needs to be a google.maps.LatLng object.
I have multiple sets of lat/long coordinates that I am using in the Google directions API with way points to get directions following roads and paths. Each set of coordinates have about 100 points which I am converting to a usable number for the start, end and waypoints.
I would like to get the lat/long values from the directions which are returned from Google. Basically get each coordinate from each road segment.
Is this possible?
Yes, by using the direction API, you would get a respond like this:
{
"status": "OK",
"geocoded_waypoints" : [
{
"geocoder_status" : "OK",
"place_id" : "ChIJ7cv00DwsDogRAMDACa2m4K8",
"types" : [ "locality", "political" ]
},
{
"geocoder_status" : "OK",
"place_id" : "ChIJ69Pk6jdlyIcRDqM1KDY3Fpg",
"types" : [ "locality", "political" ]
},
{
"geocoder_status" : "OK",
"place_id" : "ChIJgdL4flSKrYcRnTpP0XQSojM",
"types" : [ "locality", "political" ]
},
{
"geocoder_status" : "OK",
"place_id" : "ChIJE9on3F3HwoAR9AhGJW_fL-I",
"types" : [ "locality", "political" ]
}
],
"routes": [ {
"summary": "I-40 W",
"legs": [ {
"steps": [ {
"travel_mode": "DRIVING",
"start_location": {
"lat": 41.8507300,
"lng": -87.6512600
},
"end_location": {
"lat": 41.8525800,
"lng": -87.6514100
},
"polyline": {
"points": "a~l~Fjk~uOwHJy#P"
},
"duration": {
"value": 19,
"text": "1 min"
},
"html_instructions": "Head \u003cb\u003enorth\u003c/b\u003e on \u003cb\u003eS Morgan St\u003c/b\u003e toward \u003cb\u003eW Cermak Rd\u003c/b\u003e",
"distance": {
"value": 207,
"text": "0.1 mi"
}
},
...
... additional steps of this leg
...
... additional legs of this route
"duration": {
"value": 74384,
"text": "20 hours 40 mins"
},
"distance": {
"value": 2137146,
"text": "1,328 mi"
},
"start_location": {
"lat": 35.4675602,
"lng": -97.5164276
},
"end_location": {
"lat": 34.0522342,
"lng": -118.2436849
},
"start_address": "Oklahoma City, OK, USA",
"end_address": "Los Angeles, CA, USA"
} ],
"copyrights": "Map data ©2010 Google, Sanborn",
"overview_polyline": {
"points": "a~l~Fjk~uOnzh#vlbBtc~#tsE`vnApw{A`dw#~w\\|tNtqf#l{Yd_Fblh#rxo#b}#xxSfytAblk#xxaBeJxlcBb~t#zbh#jc|Bx}C`rv#rw|#rlhA~dVzeo#vrSnc}Axf]fjz#xfFbw~#dz{A~d{A|zOxbrBbdUvpo#`cFp~xBc`Hk#nurDznmFfwMbwz#bbl#lq~#loPpxq#bw_#v|{CbtY~jGqeMb{iF|n\\~mbDzeVh_Wr|Efc\\x`Ij{kE}mAb~uF{cNd}xBjp]fulBiwJpgg#|kHntyArpb#bijCk_Kv~eGyqTj_|#`uV`k|DcsNdwxAott#r}q#_gc#nu`CnvHx`k#dse#j|p#zpiAp|gEicy#`omFvaErfo#igQxnlApqGze~AsyRzrjAb__#ftyB}pIlo_BflmA~yQftNboWzoAlzp#mz`#|}_#fda#jakEitAn{fB_a]lexClshBtmqAdmY_hLxiZd~XtaBndgC"
},
"warnings": [ ],
"waypoint_order": [ 0, 1 ],
"bounds": {
"southwest": {
"lat": 34.0523600,
"lng": -118.2435600
},
"northeast": {
"lat": 41.8781100,
"lng": -87.6297900
}
}
} ]
}
Where you can get the lat/lng of each turning points under steps. You can even decode the polyline to get the set of points which describe the road.
I just discovered the Geocoder gem and my question is related to how to test it's use through Rspec.
As I have seen here How to test geocoder gem
I created a google_data.json to simulate the googlemaps response in order to no hit their API everytime and to not consume my daily request amount (moreover in this way test are really faster). My problem comes when I want to test a function like this one
def self.find_by_radius_from_location(location, radius=10)
coords = Geocoder.coordinates(location)
Garage.near(coords, radius, units: :km)
end
and here is my test (which works if I connect to gmaps api)
describe 'find_by_radius_from_location' do
let!(:garage_inside_radius) { FactoryGirl.create(:turin_garage) }
let!(:garage_outside_radius) { FactoryGirl.create(:rome_garage) }
context 'given a city' do
it 'should return one garage' do
garages = Garage.find_by_radius_from_location('Torino', 10)
garages.first.should eq(garage_inside_radius)
raise garages.inspect
ids = garages.collect { |g| g[:id] }
ids.count.should be(1)
end
end
end
The garages coord are right (the test pass if I connect to gmaps) what is wrong is my json, because I receive 2 garages instead of 1.
Here it is
{
"status": "OK",
"results": [ {
"types": [ "street_address" ],
"formatted_address": "Via Monginevro 162, Torino, Italy",
"address_components": [ {
"long_name": "Via Monginevro 162",
"short_name": "Via Monginevro 162",
"types": [ "route" ]
}, {
"long_name": "Torino",
"short_name": "Torino",
"types": [ "city", "political" ]
}, {
"long_name": "Italy",
"short_name": "IT",
"types": [ "country", "political" ]
} ],
"geometry": {
"location": {
"lat": 45.0647,
"lng": 7.63015
}
}
}, {
"types": [ "street_address" ],
"formatted_address": "Via G. Ferraris 2/4, Roma, Italy",
"address_components": [ {
"long_name": "Via G. Ferraris 2/4",
"short_name": "Via G. Ferraris 2/4",
"types": [ "route" ]
}, {
"long_name": "Roma",
"short_name": "Roma",
"types": [ "city", "political" ]
}, {
"long_name": "Italy",
"short_name": "IT",
"types": [ "country", "political" ]
} ],
"geometry": {
"location": {
"lat": 41.8084,
"lng": 12.3015
}
}
} ]
}
What's wrong with that? Is there any way to test my find_by_radius_from_location function ? I suppose I should receive only one Garage but I receive 2... Why?
EDIT
I have found a workaround but maybe there is a better way to achieve this.
let!(:garage_inside_radius) { FactoryGirl.create(:turin_garage) }
let!(:garage_outside_radius) { FactoryGirl.create(:rome_garage) }
let(:outside_coords) { { latitude: 41.8084, longitude: 12.3015 } }
before(:each) do
garage_outside_radius.update_attributes(outside_coords)
end