-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Create Request independently from the client? #385
Comments
It's possible to make and use a |
I read my first comment and I realised that I was not really clear. I would like to be able to create a // API Host and method are known here
let req_uri = reqwest::Url::parse("https://www.some.com/api/").unwrap();
let mut req = reqwest::Request::new(reqwest::Method::POST, req_uri);
// A test is done to determine if a body needs to be attached
if let Some(body) = potential_body() {
let bytes = serde_json::ser::to_vec(&body).unwrap();
*req.body_mut() = Some(reqwest::Body::from(bytes));
};
if is_protected() {
req.headers_mut()
.insert("Header", "Some Value".parse().unwrap());
} It is doable but playing with mutable references does not sound really nice. A Currently, there is two ways to obtain one
RequestBuilder::new(client: Client, request: ::Result<Request>)
pub fn request<U: IntoUrl>(&self, method: Method, url: U) -> RequestBuilder I would expect to be able to create a instance of the builder without requiring any dependencies on // Or RequestBuilder::new()
let req = Request::builder()
.method(Method::Get)
.uri("http://some.com/api")
.header("User-Agent", "Some-Agent")
.timeout(Duration::from_sec(10))
.body(()) // Or .body((())).build() |
Related: would it be possible to directly support the types in the |
I'd also be interested in something like this, or another pattern for "specify everything I need to know to execute a request" that I can then hand to a |
I've been thinking about this and I have a potential solution. ProblemThere are currently two ways to build and send a request:
The docs for
This is understandable when weighing the two options above. But it's unfortunate that I can't have the best of both worlds. I think the crux of the problem is that My suggestionGoals
ChangesTo be added
To be deprecated or removed
Unfortunately this is quite invasive. But I think it is worth it as it creates a more flexible and consistent API. Note: I am taking some inspiration from Java's java.net.http package (for example see HttpRequest). This was introduced with Java 11 (so it's kinda new) and I think it is a good comparison, very similar goals. A further consideration from that API is the way the request builder accepts the body with the http method such as |
I have the same need.
Would it be ok as a workarround to do Or is there any issue doing that ? |
It'd be really nice to have all the conveniences in A use case (which may be misguided, I'm fairly new to all this): I'm trying to implement some oauth middleware which will grab a new token (using a refresh token) when a 201 is received after sending a request. This means I need to craft a new request in middleware, where I don't have a client. Would one possible way forward be to: Create a new |
@seanmonstar I took a swing at what this might look like here |
I will be happy if this implementation is valided ! |
This can be implemented without any changes to reqwest by using To support any parts of the reqwest builder that aren't on the http crate (e.g. the timeout field), add them as extensions, and provide a custom conversion. E.g. this compiles: use std::time::Duration;
use http::Method;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let http_request = http::Request::builder()
.header("User-Agent", "Some-Agent")
.method(Method::GET)
.timeout(Duration::from_secs(10))
.body("")?
.try_into_reqwest_response()?;
Ok(())
}
trait RequestBuilderExt {
fn timeout(self, timeout: Duration) -> Self;
}
impl RequestBuilderExt for http::request::Builder {
fn timeout(self, timeout: Duration) -> Self {
self.extension(TimeoutExtension(timeout))
}
}
#[derive(Debug, Clone)]
struct TimeoutExtension(Duration);
trait TryIntoReqwestResponse {
fn try_into_reqwest_response(self) -> Result<reqwest::Request, reqwest::Error>;
}
impl<T: Into<reqwest::Body>> TryIntoReqwestResponse for http::Request<T> {
fn try_into_reqwest_response(self) -> Result<reqwest::Request, reqwest::Error> {
let timeout = self.extensions().get::<TimeoutExtension>().cloned();
let mut reqwest_request = reqwest::Request::try_from(self)?;
if let Some(timeout) = timeout {
*reqwest_request.timeout_mut() = Some(timeout.0);
}
Ok(reqwest_request)
}
} There's some prior suggestions that this was going to be done at hyperium/http#183 as well as a fairly detailed background on extensions in hyperium/http#395 I suspect that it would be a good idea for reqwest to add an extension trait with methods like timeout above on |
I would like to create and modify a
Request
object independently from aClient
.Actually, the API kind of enforce the creation of a
RequestBuilder
through aClient
instance.Is there any reason to this? Is it planned to update the API of
RequestBuilder
to offer a way to constructRequest
like:The text was updated successfully, but these errors were encountered: