1

I want to use reqwest to make a request, then print the response's body and return a reqwest::Error if the status code was >= 400. This is how I would like to do this:

pub async fn print_body() -> Result<(), reqwest::Error> {
    let response = reqwest::get("https://www.rust-lang.org").await?;
    println!("received text: {:?}", response.text().await?);
    response.error_for_status()?;
    Ok(())

The trouble is that both response.text() and response.error_for_status() consume the response. Debug printing the response itself or the error from response.error_for_status() does not print the response body.

I've tried saving the status code, then generating a reqwest::Error if the status code is >= 400, but reqwest::Error is not meant to be constructed by library users since its inner field and constructor are private. Ideally a reqwest::Error is returned since other functions depend on this API, and I would like to understand if it's possible to achieve this without changing the public interface.

Rust playground link

reqingball
  • 13
  • 4

3 Answers3

2

You might have glossed over the error_for_status_ref() method, which does not consume the response. You just need to swap the order of the calls:

pub async fn print_body() -> Result<(), reqwest::Error> {
    let response = reqwest::get("https://www.rust-lang.org").await?;
    response.error_for_status_ref()?;
    println!("received text: {:?}", response.text().await?);
    Ok(())
}

To print the text regardless, just store the result of error_for_status_ref() and map the reference in the Ok case to be () to match the return type of your function:

pub async fn print_body() -> Result<(), reqwest::Error> {
    let response = reqwest::get("https://www.rust-lang.org").await?;
    let result = response.error_for_status_ref().map(|_| ());
    println!("received text: {:?}", response.text().await?);
    result
}
cdhowie
  • 158,093
  • 24
  • 286
  • 300
2

There is no issue if you handle your error case before you retreive the text as error_for_status returns the Response if everything is ok:

pub async fn print_body() -> Result<(), reqwest::Error> {
    let response = reqwest::get("https://www.rust-lang.org").await?;
    println!("received text: {:?}", response.error_for_status()?.text().await?);
    Ok(())
}
cafce25
  • 15,907
  • 4
  • 25
  • 31
  • Yea right, since you and cdhowie already provided solutions using `_ref` I just removed that one. – cafce25 Feb 23 '23 at 23:33
0

Thank you, @cafce25 for pointing me back to error_for_status_ref, which I originally passed over since it returns a reference to self on Ok(), giving me compiler errors if I tried to keep the full result to use after calling .text(). But grabbing just the error with .err() resolves it:

pub async fn print_body() -> Result<(), reqwest::Error> {
    let response = reqwest::get("https://www.rust-lang.org").await?;
    let maybe_err = response.error_for_status_ref().err();
    println!("received text: {:?}", response.text().await?);
    match maybe_err {
        Some(e) => Err(e),
        None => Ok(()),
    }
}
reqingball
  • 13
  • 4