3

When I run the following code:

use exitfailure::ExitFailure;
use reqwest::Url;
use serde_derive::{Deserialize, Serialize};
use std::env;

#[derive(Serialize, Deserialize, Debug)]
struct CompanyInfo {
    country: String,
    currency: String,
    exchange: String,
    ipo: String,
    marketCapitalization: u128,
    name: String,
    phone: String,
    shareOutstanding: f64,
    ticker: String,
    weburl: String,
    logo: String,
    finnhubIndustry: String,
}

impl CompanyInfo {
    async fn get(symbol: &String, api_key: &String) -> Result<Self, ExitFailure> {
        let url = format!(
            "https://finnhub.io/api/v1/stock/profile2?symbol={}&token={}",
            symbol, api_key
        );

        let url = Url::parse(&*url)?;
        let res = reqwest::get(url).await?.json::<CompanyInfo>().await?;

        Ok(res)
    }
}

#[tokio::main]
async fn main() -> Result<(), ExitFailure> {
    let api_key = "MY API KEY".to_string();
    let args: Vec<String> = env::args().collect();
    let mut symbol: String = "AAPL".to_string();

    if args.len() < 2 {
        println!("Since you didn't specify a company symbol, it has defaulted to AAPL.");
    } else {
        symbol = args[1].clone();
    }

    let res = CompanyInfo::get(&symbol, &api_key).await;
    println!("{:?}", res);

    Ok(())
}

I get an error: Err(error decoding response body: expected ',' or '}' at line 1 column 235). For another API, this code with a similar structure worked. How do you solve this issue with reqwest?

Henry Boisdequin
  • 325
  • 1
  • 3
  • 9
  • 1
    "How do you solve this issue with reqwest?" you don't because the issue seems to be with the API? If the response is not valid JSON (which it doesn't seem to be given the error) there's not much reqwest can do about it. You should get the response separately (e.g. via curl/wget) and confirm that it's always a proper and complete json. Note that some APIs don't return JSON documents in case of errors (non-200 responses). If that's the case here then you will need to first handle the HTTP error scenario, and only if you know you have a successful response try to decode it. – Masklinn Jan 17 '21 at 16:05

1 Answers1

8

Typically, the error decoding response body means that you tried to deserialize an HTTP response that is in a given format, but the response body wasn't valid for that format. In your case, you are trying to deserialize JSON, so the error means that the thing you are trying to deserialize probably isn't valid JSON, or perhaps it is valid JSON but your expected JSON structure doesn't match the structure returned from the server. The server might have goofed in creating it's JSON, or perhaps it is returning a response body that isn't actually JSON for a specific reason (for example, some APIs will not return JSON if they are returning a 500 response).

In order to debug and fix this, you need to know exactly what the response body looks like that you are attempting to parse. One way to do this is to split the parsing of the code into two parts: one that gets the text, and another that tries to parse. For example, for debugging purposes you can print out the response that you have received by doing something like the following:

// Split up the JSON decoding into two steps.
// 1.) Get the text of the body.
let response_body = reqwest::get(url).await?.text().await?;
println!("Response Body: {}", response_body);

// 2.) Parse the results as JSON.
let res: CompanyInfo = serde_json::from_str(&response_body)?;

This code should will probably fail just as before, but now you'll have the response body that failed printed out. At that point, you'll have to analyze the response body, at which point it will hopefully become obvious why it doesn't work.

Mark Hildreth
  • 42,023
  • 11
  • 120
  • 109
  • I get this: Response Body: {"country":"US","currency":"USD","exchange":"NASDAQ NMS - GLOBAL MARKET","finnhubIndustry":"","ipo":"2010-06-29","logo":"https://static.finnhub.io/logo/2dd96524-80c9-11ea-aaac-00000000092a.png","marketCapitalization":783117.67,"name":"Tesla Inc","phone":"16506815000.0","shareOutstanding":905,"ticker":"TSLA","weburl":"https://www.tesla.com/"} – Henry Boisdequin Jan 18 '21 at 01:43
  • It looks like to it is valid JSON but it still errors out at the JSON parsing. – Henry Boisdequin Jan 18 '21 at 01:44
  • 1
    @HenryBoisdequin That is valid JSON, but not for your structure. Your structure includes a `marketCapitalization` field, which the response you've shown does not. As a result of the missing field, a `CompanyInfo` structure could not be fully deserialized, hence the error. I was able to figure this out by running this through the Rust Playground, which shows the full error: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=af20de9b3f6eda2a10f5f8f1780d8ab2 – Mark Hildreth Jan 18 '21 at 02:08