Skip to content
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

example of how to implement 'a scoped method that accepts a type bound by IntoBody<'a> #352

Closed
softprops opened this issue Feb 28, 2015 · 2 comments

Comments

@softprops
Copy link
Contributor

I'm writing an http client using hyper and an running into some design issues with IntoBody<'a>. I like that the type of fleible enough to adapt arbitrary types in into Body<'a>s.

I'm having trouble what/where other things need annotated with 'a. I've put the following
in an impl<'a> Client definition to put 'a in scope of all methods. But I end up with the rustc error
error:clidoes not live long enough on the line cli.request... For clients interfaces with IntoBody or Body directly is there a recommended usage for what to annotate with with the 'a lifetime marker?

 fn req<B: IntoBody<'a>>(&mut self, path: String, body: Option<B>, method: Method) -> Result<String> {
     let mut cli = hyper::Client::new();
     let uri = Url::parse(&format!("{}/api/v1{}", self.host, path)).ok().expect("invalid url");
     let bound = cli.request(method, uri)
        .header(UserAgent("mylib/0.1.0".to_string()))
        .header(Accept(vec![qitem(Mime(Application, Json, vec![(Attr::Charset, Value::Utf8)]))]))
        .header(ContentType(Mime(Application, Json, vec![(Attr::Charset, Value::Utf8)])));
      let authenticated = match self.token.clone() {
        Some(auth) => bound.header(Authorization(auth)),
                 _ => bound
      };
      let embodied = match body {
        Some(data) => authenticated.body(data.into_body()),
                _  => authenticated
      };
      let mut res = match embodied.send() {
        Ok(r) => r,
        Err(err) => panic!("failed request: {:?}", err)
      };
      res.read_to_string()
  }

Another thing I tried was to have the method itself be parameterized with 'a but I wasn't sure if I'm just misunderstanding its usage

fn req<'a, B: IntoBody<'a>> ...

Unrelated to the 'a question, is it recommended to store a single to a client instance in a struct or is it better to create a new instance for each request as I'm doing here?

@seanmonstar
Copy link
Member

  1. The 'a lifetime means that the value needs to live at least as long as some time 'a. The time period is not the lifetime of the entire Client. A Client can make many requests, and doesn't need to keep around a body forever. The body only needs to live as long as it takes for the Client to write it into the request body. So, you'd be best confining the lifetime to a function, where some borrowed body (like &str) can live for as long as the function executes, writing the body to the request, and then releasing the borrow.

    I recommend reading up on ownership and lifetimes. I'd also recommend asking questions such as these on StackOverflow, as they are more general about Rust, and there are more people around to provide you an answer more quickly.

  2. If feasible, you should create one Client, and use it for all requests (unless you need clients with different behavior). Once Implement keep-alive #41 is completed, the Client will include a ConnectionPool that will allow subsequent requests to use the same connection, making things much faster.

@softprops
Copy link
Contributor Author

Thanks again for you patience @seanmonstar

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants