georust/geocoding

Forward geo error: invalid type: sequence, expected a string

AppyCat opened this issue · 18 comments

use geocoding::{Opencage, Forward, Point}; - using version 0.3.1 in cargo.toml

let oc: Opencage = Opencage::new("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".to_string());
let address = "Schwabing, München";
let res: Vec<Point> = oc.forward(&address).unwrap();
let first_result = &res[0];

The third line above responds with the error below:

thread 'main' panicked at 'called Result::unwrap() on an Err value: Error { kind: Json(Error("invalid type: sequence, expected a string", line: 1, column: 393)), url: None }', src/main.rs:91:53

Could it be due to a change in API with OpenCage? I tried OpenStreetMap too, which also responds with a type error. 3rd option not workable as it's limited to Switzerland vs being worldwide.

Use case is to get long lat by address (city, state, zip, country).

Hi,

Ed from OpenCage here.

Can you establish at all what is causing the error, I mean which part of the response it is dying on?

The most recent change was over a month ago (see Change Log), which I suppose this could be related to.

Basically in the components portion of the response there can now be a key ISO_3166-2 which is a list of ISO 3166-2 codes for the location. Here is a detailed blog post describing the addition to the API.

I hope that helps.

Hi Ed, thank you for your quick response.

The line throwing the error is:

let res: Vec<Point> = oc.forward(&address).unwrap();

And the error is:

thread 'main' panicked at 'called Result::unwrap() on an Err value: Request(reqwest::Error { kind: Decode, source: Error("invalid type: sequence, expected a string", line: 1, column: 392) })', src/main.rs:91:53

I am trying to do a forward search to get longitude and latitude by an address which would typically be city, state, zip & country. I tried an ISO_3166-2 country code, but am still getting the above error over invalid type sequence.

Tried this code with the latest version of your library. Let me now if there's any more information I can share so we can figure ths out. Thanks again.

sorry, I guess I am not formulating my question clearly. Yes, I see the error message, it was posted in the initial message in this thread. My question is which part of the JSON is causing this errror in the decoding? Which content is at "column 392"?
Please bear in mind I know nothing about Rust and am not the maintainer of this module.

Our API is returning:

     ...
      "components": {
        "ISO_3166-1_alpha-2": "DE",
        "ISO_3166-1_alpha-3": "DEU",
        "ISO_3166-2": [
          "DE-BY"
        ],
        "_category": "place",
        "_type": "neighbourhood",
        "city": "München",
        "city_district": "Schwabing-Freimann",
        "continent": "Europe",
        "country": "Deutschland",
        "country_code": "de",
        "political_union": "European Union",
        "postcode": "80805",
        "state": "Bayern",
        "state_code": "BY",
        "suburb": "Schwabing"
      },

my guess is it is the newly-added ISO_3166-2 that is causing problems as Rust is expecting the value to be a string, not a list. Please see the blog post to understand why it needs to be a list (in short: many countries have multiple ISO 3166-2 codes).

b4l commented

@freyfogle this seems to be the issue indeed as components is defined as a HashMap<String, String> https://github.com/georust/geocoding/blob/master/src/opencage.rs#L535.

Hi Ed, I'm not feeding or getting any json.

Thanks for the update Balthasar. What would you recommend I try to resolve this or will it require a update in the crate ref the type issue?

b4l commented

Probably can test this by replacing the String value with something like HashMap<String, Component>

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Component {
    String(String),
    List(Vec<String>),
}

or HashMap<String, serde_json::Value>

Hi Ed, I'm not feeding or getting any json.

yes, you are getting back JSON when you query our API

Please see pur demo page: https://opencagedata.com/demo
Put in the query "Schwabing, München" and you can see exactly the JSON we are returning.

Bildschirmfoto 2022-06-25 um 13 08 18

or HashMap<String, serde_json::Value>

That seems to work. @b4l would you like to push a PR with the fix?

b4l commented

@urschrei yes, I can do that.

You guys are awesome, thank you fo the refactor :)

Ed, thanks for your help, you're a gentleman & scholar.

On slightly diff point, in Postgres do you have a preference on radius search by distance. Options are:

PostGiS geometry
PostGIS geography
Cube EarthDistance

v0.4.0 is on crates.io, with the fix. Thanks @freyfogle and @b4l for the diagnosis and PR

Just tried v0.4.0. Am getting this error now trying it in async main function in Actix Web:

thread 'main' panicked at 'Cannot drop a runtime in a context where blocking is not allowed. This happens when a runtime is dropped from within an asynchronous context.', /Users/test/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.19.2/src/runtime/blocking/shutdown.rs:51:21

That error doesn't originate in geocoding I'm afraid.

That's a good thing. Seems to be a Tokio issue, will test again. Is it possible to run gecoding async?

b4l commented

@AppyCat this seems to be expected, resulting from how the blocking reqwest Client interacts with the tokio runtime: seanmonstar/reqwest#1017

I got it working by spawning a new thread, so that's a workable solution:

thread::spawn(move || {
let oc: Opencage = Opencage::new("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".to_string());
let address = "Schwabing, München";
let res: Vec<Point> = oc.forward(address).unwrap();
println!("lon {} lat {}", res[0].x(), res[0].y());
});

Are there any key differences between Opencage and Openstreetmap?

Perhaps it may be an idea to address in the docs how the Client interacts with the Tokio runtime, with a suggestion or an example of working around that. Thanks again.

Hi yes, there are many differences between OpenStreetMap and OpenCage.
I dont think the rust SDK is really the place for the discussion

Spend some time reading the OpenCage geocoding API docs.

Thanks, Geocoding resolves the current use case. Will check docs on both APIs in a few days.