reqwest: Can't use relative URLs for making requests

When trying to pass a relative URL to any of the functions like .get, it errors with RelativeUrlWithoutBase. From my understanding, this is triggered by the url crate because Url::parse only accepts absolute URLs.

My expectation would have been that I can set the Host header in the default header map on the client instance and later on use relative URLs to actually make requests.

Is this something that is planned to be supported?

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 39
  • Comments: 18 (6 by maintainers)

Commits related to this issue

Most upvoted comments

Another independent use case for this is for the WASM browser target. It would be convenient for clients to be able to specify relative URLs from the host they are on

FWIW I was just searching for a similar feature for integration tests, thought being that instead of creating a client in each test and passing an address, I could just generate a client which points at the locally running server and pass that to each test. Not a big deal, but would reduce a couple of lines of boilerplate per test.

Instead of this:

let address = spawn_server();
let client = reqwest::Client::new();

let response = client.get(format!("{address}/some-path"));

I could have this:

let client = spawn_server();

let response = client.get("/some-path");

Although in reality it’d probably be a reusable rtest fixture so I can make my Rust server tests as easy to write as FastAPI tests. And that brings me to my answer to this:

Are there other clients that support that?

Coming from the Python world, httpx has this feature. It’s the most popular of the “modern” (i.e., async capable) request libraries.

In the Rust world, surf supports this syntax as well. I don’t think any of the others I’ve tried do.

This would be cool to have.

on wasm, for yew or other, you can get the base url (https://youraddress.com) with

let baseurl = web_sys::window().unwrap().origin();

reqwasm also supports relative urls.

Here is a way around using relative paths

use reqwest::{header, Response, Error};
use serde::{Deserialize, Serialize};

pub struct HttpClient {
    base_url: String,
    headers: header::HeaderMap,
   pub client: reqwest::Client,
}

impl HttpClient {
    pub fn new(base_url: &str, headers: header::HeaderMap) -> Result<Self, Error> {
        let client = reqwest::Client::builder().build()?;
        Ok(Self {
            base_url: base_url.to_owned(),
            headers,
            client,
        })
    }

    pub async fn get<T>(&self, path: &str) -> Result<T, Error>
    where
        T: for<'de> Deserialize<'de>,
    {
        let url = format!("{}{}", self.base_url, path);
        let response = self.client.get(&url).headers(self.headers.clone()).send().await?;
        let json = response.json::<T>().await?;
        Ok(json)
    }

    pub async fn post<T>(&self, path: &str, body: &T) -> Result<Response, Error>
    where
        T: Serialize,
    {
        let url = format!("{}{}", self.base_url, path);
        let resp = self.client
            .post(&url)
            .headers(self.headers.clone())
            .json(body)
            .send()
            .await?;

        Ok(resp)
    }
}

Are there other clients that support that?

surf allows one to specify a base_url in the client config builder and then allows relative urls in requests made using that client.

Hello,

python httpx supports base_url on the Client builder

https://www.python-httpx.org/advanced/#other-client-only-configuration-options

Axum’s TestClient helper (for integration testing) might be a useful example for anyone looking for a simple wrapper around some of Client’s methods to allow for relative URLs, but this is opinionated towards Axum integration testing:

https://github.com/tokio-rs/axum/blob/main/axum/src/test_helpers/test_client.rs

And if you happen to be specifically looking for a solution for Axum integration testing, it’s also available in a crate: https://crates.io/crates/axum-test-helper

Are there other clients that support that?

request, the major node (javascript) HTTP client library, does.