How to make function that returns text from response?

1.3k Views Asked by At

I am new to rust, and trying to learn it after python, and have faced to problem in one of the simplest tasks.
For simplicity I want to write function to get data(in this example - text) from http response.
src/main.rs

use reqwest;


fn main() {
    let text = get_text();
    println!("Got text {text}")
}

fn get_text() -> String {
    let http_client = reqwest::blocking::Client::new();
    let url = "https://google.com";
    let response = http_client.get(url).send()?.text()?;
    response
}

Cargo.toml

[package]
name = "test"
version = "0.1.0"
edition = "2021"
[dependencies]
reqwest = { version = "0.11", features = ["json", "blocking"] }
openssl = { version = "0.10", features = ["vendored"] }

I want to make get_text() routine to return String type.
According to reqwest docs .text() returns Result<String>
As I understand operator ? means that call should return Ok<String> or panic with Err(e)

With that code compilation fails:

 let response = http_client.get(url).send()?.text()?;
cannot use the `?` operator in a function that returns `std::string::String`

Here I do not understand first thing:
Why compile compare function return type with return of both .send() and .text()? if return value is only after that?

And, well, I try to change return type to Result<String, Box<dyn std::error::Error>> as in documentation and examples
and then compilator whines about wrong return type:

 |     response
 |     ^^^^^^^^ expected enum `Result`, found struct `std::string::String`

So the second question is:
How i can achieve my goal while compilators compare return type in the middle of function call and in the end of call

2

There are 2 best solutions below

0
On BEST ANSWER

First and foremost have a good read here about ? operator for answer of first question.

The ? placed after a Result value is defined to work in almost the same way as the match expressions we defined to handle the Result values

About your code you should do something like below

use reqwest;

// Have changed main method's return type 
// as using ? operator on result returned by get_text() method
fn main() -> Result<(), Box<dyn std::error::Error>> {

    // unwrapped result from get_text() with ?
    let text = get_text()?;

    // changed formatting
    println!("Got text {}", text);

    // as main method response type is changes return unit type in case of success
    Ok(())
}

fn get_text() -> Result<String, Box<dyn std::error::Error>> {
    let http_client = reqwest::blocking::Client::new();
    let url = "https://google.com";

    let response = http_client
        // form a get request with get(url)
        .get(url)
        // send the request and get Response or else return the error
        .send()?
        // get text from response or else return the error
        .text()?;

    // wrapped response in Result
    Ok(response)
}

Hope it helpls.

0
On

The question mark operator passes on an intermediate Result::Err value by returning it. This means that the function must have Result as its return type. But at the end of the function you try to return a String. A String is not a Result variant, but you can make it into one by wrapping it in Ok.

Alternatively if you want do not mind panics, then instead of '?' you could use '.unwrap()' and then your return type could stay String.