user2586455
user2586455

Reputation: 601

Google Places API Web Service Server Side Solution

I've been struggling through this for a few days now - I've got it working how I want but then I keep running into roadblocks which I will describe below. It's got to the point where I just need to ask for some advice from someone who has the necessary experience.

So this is what I ultimately want to achieve:

  1. Web page loads and the user sees their local area on a Google Map
  2. There are a list of brands next to the map, such as "Tesco" and "Walmart" for example
  3. When the user clicks on Walmart, they would see all Walmart stores in their local area on the map - when the map markers are clicked, the popup will contain the store name, address etc.

Pretty simple in terms of functionality really.

I originally was using the Google Maps JavaScript API together with the Google Places API JavaScript Library.

I got the basic functionality working, but ran into the OVER_QUERY_LIMIT problem.

I discovered this happens because of the simultaneous requests being made (nothing to do with the daily usage limits); for example when the user clicks "Walmart", trying to show ~10+ stores on the map at the same time is blocked by Google.

From my research, it looked like I'd have to use the Google Maps API Web Services instead.

If too many requests are made within a certain time period, the API returns an OVER_QUERY_LIMIT response code. The per-session rate limit prevents the use of client-side services for batch requests. For batch requests, use the Maps API web services.

So I also got it all working for a 2nd time using the Google Places API Web Service which I was pretty pleased about. I'm using AJAX to request the JSON from Google, but now I get the following console error:

XMLHttpRequest cannot load https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=53.000403,-1.129625&radius=10000&name=Sainsbury's|Debenhams&key=API_KEY. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.

I know I'm getting this error because I'm requesting from a different server/domain. Here's my code, which I'm just running locally at the moment:

accessURL = "https://maps.googleapis.com/maps/api/place/nearbysearch/json?location="+userCords.latitude+","+userCords.longitude+"&radius=10000&name=Sainsbury's|Debenhams&key=API_KEY"; 

$.ajax({
  type: "GET",
  contentType: "application/json; charset=utf-8",
  url: accessURL,
  dataType: 'json',
  success: function (data) {

    $.each(data.results, function (i, val) {
      storeId.push(val.place_id);
      storeName.push(val.name);
    });

    //Now, use the id to get detailed info
    $.each(storeId, function (k, v){
      $.ajax({
        type: "GET",
        contentType: "application/json; charset=utf-8",
        url: "https://maps.googleapis.com/maps/api/place/details/json?placeid="+v+"&key=API_KEY",
        dataType: 'json',
        success: function (data) {

          var latitude = data.result.geometry.location.lat;
          var longitude = data.result.geometry.location.lng;

          //set the markers.      
          myLatlng = new google.maps.LatLng(latitude,longitude);

          allMarkers = new google.maps.Marker({
            position: myLatlng,
            map: map,
            title: data.result.name,
            html: '<div class="marker-content">' +
                '<p>'+data.result.name+'</p>' +
                  '<p>'+data.result.formatted_address+'</p>' +
                '</div>'
          });

          //put all lat long in array
          allLatlng.push(myLatlng);

          //Put the markers in an array
          tempMarkerHolder.push(allMarkers);

          google.maps.event.addListener(allMarkers, 'click', function () {
            infowindow.setContent(this.html);
            infowindow.open(map, this);
          });

          //  Make an array of the LatLng's of the markers you want to show
          //  Create a new viewpoint bound
          var bounds = new google.maps.LatLngBounds ();
          //  Go through each...
          for (var i = 0, LtLgLen = allLatlng.length; i < LtLgLen; i++) {
            //  And increase the bounds to take this point
            bounds.extend (allLatlng[i]);
          }
          //  Fit these bounds to the map
          map.fitBounds (bounds);


        }
      });
    }); //end .each
  }
});

For testing, I've used this https://crossorigin.me prepended onto the API access urls to temporarily get around this issue, but now I actually need to solve the problem properly.

After some research, I saw a lot of people advising to change the dataType to jsonp. But when I do that, I get the following console error:

https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=53.041981899999996,-1.1898794&radius=10000&name=Sainsbury%27s|Debenhams&key=API_KEY&callback=jQuery111309486707670378429_1491079656734&_=1491079656735:2 Uncaught SyntaxError: Unexpected token :

After even more research into that latest error, I'm seeing things like "looks like the places api doesn't support ajax or jsonp", which is extremely annoying after I got it all working already!

Then I saw this:

The Google Places API Web Service is for use in server applications. If you're building a client-side application, take a look at the Google Places API for Android and the Places Library in the Google Maps JavaScript API.

Which means I've now gone full circle!

I'm at the point where I guess I have to work out a server-side solution instead of a client-side one. But honestly, I have no idea where to go from here and can't find anything online to point me in the right direction.

Can anyone please advise what to do next? What would a "server-side solution" look like? I've come this far, I really don't want to quit now! Any help would be hugely appreciated!

Upvotes: 1

Views: 4423

Answers (2)

Sun
Sun

Reputation: 75

I got the same OVER_QUERY_LIMIT message about sending 90 requests, Here is some solutions sort out from the stackOverFlow:

  1. delay the request
  2. if OVER_QUERY_LIMIT, retry this request
  3. change the request from clientService to webService.See more from google api document

so I try to delay my requets, this can not prevent OVER_QUERY_LIMIT ,but will greatly reduce frequency.Here is my core function about google map api direction, just like your google map place Api.

function calculateDirections( directionsService, requestList, responseList, deferred, recursiveCount ) {
            var deferred = deferred || $q.defer();
            var responseList = responseList || [];
            var recursiveCount = recursiveCount || 0;
            var directionRequest = {
                origin: requestList[ recursiveCount ].origin,
                destination: requestList[ recursiveCount ].destination,
                waypoints: requestList[ recursiveCount ].waypoints,
                optimizeWaypoints: false,
                travelMode: google.maps.TravelMode.DRIVING
            };

            directionsService.route( directionRequest, function ( response, status ) {
                if ( status === google.maps.DirectionsStatus.OK ) {
                    responseList.push( response );
                    if ( requests.length > 0 ) {
                        //delay google request,millisecond
                        setTimeout( function () {
                            recursiveCount++;
                            calculateDirections( directionsService, requests, responseList, deferred, recursiveCount );
                        }, recursiveCount * 10 + 500 );

                    } else {
                        deferred.resolve( responseList );
                    }
                }else if( status === google.maps.DirectionsStatus.OVER_QUERY_LIMIT ){
                    //try again google request
                    setTimeout( function () {
                        calculateDirections( directionsService, requests, responseList, deferred, recursiveCount );
                    }, recursiveCount * 10 + 500 );
                } else {
                    var result = {};
                    result.status = status;
                    deferred.reject( result );
                }

            } );

            return deferred.promise;
}

Upvotes: 0

xomena
xomena

Reputation: 32178

To solve the issue you should build your own intermediate server that will send requests to Google (server side requests) and pass the JSON responses back to your client side application. In other words you should build a proxy to avoid the CORS issue.

How you build the proxy server, it's completely up to you. Choose the technology you are familiar with (Java, Python, NodeJs, etc.) and implement a server side code.

The client side code will send requests to intermediate server, intermediate server will send HTTPS request to Google and pass the response back to client side.

There are several useful libraries on GitHub that you can use server side with NodeJs, Java, Python or Go:

https://github.com/googlemaps/google-maps-services-js

https://github.com/googlemaps/google-maps-services-java

https://github.com/googlemaps/google-maps-services-python

https://github.com/googlemaps/google-maps-services-go

Hope it helps!

Upvotes: 0

Related Questions