3

I'm trying to call HERE geocoder API, but on a valid url call the response body isn't fully initialized.

As shown below, I simply call a the API providing a valid url:

val url = UriComponentsBuilder.fromUriString(properties.geocodeUrl)
    .queryParam("app_id", properties.appId)
    .queryParam("app_code", properties.appCode)
    .queryParam("searchtext", "10 Downing Street, London")
    .toUriString()

logger.debug("calling geocoder rest service: $url")

val geocoderResponse = RestTemplate().getForObject<GeocoderResponse>(url)

GeocoderResponse

package com.gudjob.geolocation

import com.fasterxml.jackson.annotation.JsonProperty
import com.gudjob.core.domain.Coordinates
import java.io.Serializable

/**
 * @author Elia Sgolmin
 */
internal data class GeocoderResponse(
    @field:JsonProperty("Response")
    var response: Response?
) : Serializable {

    data class Response(
        @field:JsonProperty("View")
        var views: List<View>
    ) : Serializable {

        data class View(
            @field:JsonProperty("Result")
            var results: List<Result>
        ) : Serializable {

            data class Result(
                @field:JsonProperty("Location")
                var location: Location?
            ) : Serializable {

                data class Location(
                    @field:JsonProperty("DisplayPosition")
                    var displayPosition: DisplayPosition?
                ) : Serializable {

                    data class DisplayPosition(
                        @field:JsonProperty("Latitude")
                        var latitude: Double?,

                        @field:JsonProperty("Longitude")
                        var longitude: Double?
                    ) : Serializable {

                        fun toCoordinates(): Coordinates {
                            val lat = latitude
                            val lon = longitude
                            return if (lat == null || lat.isNaN() || lon == null || lon.isNaN())
                                Coordinates.Unavailable
                            else
                                Coordinates.Available(lat, lon)
                        }
                    }
                }
            }
        }
    }
}

If I copy the logged url and use it in browser or postman I get the following expected response

{  
   "Response":{  
      "MetaInfo":{  
         "Timestamp":"2019-02-26T14:03:09.236+0000"
      },
      "View":[  
         {  
            "_type":"SearchResultsViewType",
            "ViewId":0,
            "Result":[  
               {  
                  "Relevance":1,
                  "MatchLevel":"houseNumber",
                  "MatchQuality":{  
                     "City":1,
                     "Street":[  
                        1
                     ],
                     "HouseNumber":1
                  },
                  "MatchType":"pointAddress",
                  "Location":{  
                     "LocationId":"NT_lWsc8knsFwVitNTFX88zmA_xAD",
                     "LocationType":"point",
                     "DisplayPosition":{  
                        "Latitude":51.50341,
                        "Longitude":-0.12765
                     },
                     "NavigationPosition":[  
                        {  
                           "Latitude":51.50322,
                           "Longitude":-0.12767
                        }
                     ],
                     "MapView":{  
                        "TopLeft":{  
                           "Latitude":51.5045342,
                           "Longitude":-0.129456
                        },
                        "BottomRight":{  
                           "Latitude":51.5022858,
                           "Longitude":-0.125844
                        }
                     },
                     "Address":{  
                        "Label":"10 Downing Street, London, SW1A 2AA, United Kingdom",
                        "Country":"GBR",
                        "State":"England",
                        "County":"London",
                        "City":"London",
                        "District":"Westminster",
                        "Street":"Downing Street",
                        "HouseNumber":"10",
                        "PostalCode":"SW1A 2AA",
                        "AdditionalData":[  
                           {  
                              "value":"United Kingdom",
                              "key":"CountryName"
                           },
                           {  
                              "value":"England",
                              "key":"StateName"
                           },
                           {  
                              "value":"London",
                              "key":"CountyName"
                           }
                        ]
                     }
                  }
               }
            ]
         }
      ]
   }
}

As you can see, "View" attribute of "Response" object is an array with one object containing latitude and longitude of the given address.

What I get instead is

GeocoderResponse(response = Response(views = []))

where response has been initialized, but views is empty.

Changing my code to get JSON response as plain text with

restTemplate().getForObject<String>(url)

it results in the following json

{"Response":{"MetaInfo":{"Timestamp":"2019-02-26T13:35:37.851+0000"},"View":[]}}

Even here "View" property is empty so I don't think the issue is about JSON deserialization.

Any suggestion?

UPDATE

I've checked RestTemplate request headers vs. browsers and postman ones, but couldn't find any relevant difference.

The only think I can point out is postman response header Content-Encoding → gzip, which is missing in Spring response.

noiaverbale
  • 1,303
  • 9
  • 24
  • Maybe response from server depends from [`Content Type`](https://stackoverflow.com/questions/477816/what-is-the-correct-json-content-type) or some other headers? Play with `postman` and try to find why it returns other response. Do you have an access to `REST` `API` method implementation you invoke? – Michał Ziober Feb 27 '19 at 21:30
  • There is no Content-Type since [Here's geocoder API](https://developer.here.com/documentation/geocoder/topics/what-is.html) uses url parameters. The only header restTemplate adds is `Accept=[application/json, application/*+json]`. Giving this parameter to postman doen't change its (correct) response. About response headers, postman gets an additional one: `Content-Encoding → gzip` (and of course `Content – noiaverbale Feb 28 '19 at 08:27
  • If you are sure everything is the same, you can do a `Unit Test` where you try to deserialise example response to object using `ObjectMapper`. It will prove that `POJO` structure fits `JSON` payload. – Michał Ziober Feb 28 '19 at 08:42
  • As I stated in my update, if I ask the response as a String, rest API responds with the quoted string and `View` is already empty, so I don't think it's a POJO problem – noiaverbale Feb 28 '19 at 09:13
  • Try GSON, I tried it with GSON. It works perfectly. – Moinkhan Mar 06 '19 at 12:19
  • @Moinkhan the issue is **not** about jackson vs. gson or others since even getting the body as a string I get empty `View`. – noiaverbale Mar 06 '19 at 14:32

1 Answers1

0

The issue might be ,the query parameter searchtext is not being URL encoded when requesting via the UriComponentsBuilder interface. Try encoding the string being passed and check the response.

.queryParam("searchtext", URLEncoder.encode("10 Downing Street, London","UTF-8"))
HERE Developer Support
  • 6,842
  • 2
  • 12
  • 20