26

I noticed that Rust doesn't have a builtin library to deal with HTTP, it only has a net module that deals with raw IP and TCP protocols.

I need to take a &str of the URL, make a HTTP GET request, and if successful return either a String or &str that corresponds to the HTML or JSON or other response in string form.

It would look something like:

use somelib::http;

let response = http::get(&"http://stackoverflow.com");
match response {
    Some(suc) => suc,
    None => panic!
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Josh Weinstein
  • 2,788
  • 2
  • 21
  • 38
  • Have you tried googling for http crates? For example, [this might work for you](https://github.com/alexcrichton/curl-rust). – user4815162342 Apr 05 '17 at 06:03
  • 2
    This kind of question is off-topic on Stack Overflow, so it likely will be closed. If you haven't found your answer by then, I invite you to check the Rust tag wiki [Getting Help](http://stackoverflow.com/tags/rust/info) section which details other venues for open-ended questions. – Matthieu M. Apr 05 '17 at 08:04

4 Answers4

19

The current best practice for this particular problem is to use the reqwest crate, as specified in the Rust Cookbook. This code is slightly adapted from the cookbook to run standalone:

extern crate reqwest; // 0.9.18

use std::io::Read;

fn run() -> Result<(), Box<dyn std::error::Error>> {
    let mut res = reqwest::get("http://httpbin.org/get")?;
    let mut body = String::new();
    res.read_to_string(&mut body)?;

    println!("Status: {}", res.status());
    println!("Headers:\n{:#?}", res.headers());
    println!("Body:\n{}", body);

    Ok(())
}

As the cookbook mentions, this code will be executed synchronously.

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
nindalf
  • 1,058
  • 2
  • 12
  • 15
15

Take a look at Hyper.

Sending a GET request is as simple as this.

let client = Client::new();

let res = client.get("http://example.domain").send().unwrap();
assert_eq!(res.status, hyper::Ok);

You can find more examples in the documentation.

Edit: It seems that Hyper got a bit more complicated since they started to use Tokio. Here is updated version.

extern crate futures;
extern crate hyper;
extern crate tokio_core;

use std::io::{self, Write};
use futures::{Future, Stream};
use hyper::Client;
use tokio_core::reactor::Core;


fn main() {
    let mut core = Core::new().unwrap();
    let client = Client::new(&core.handle());

    let uri = "http://httpbin.org/ip".parse().unwrap();
    let work =
        client.get(uri).and_then(|res| {
            println!("Response: {}", res.status());

            res.body().for_each(|chunk| {
                io::stdout()
                    .write_all(&chunk)
                    .map_err(From::from)
            })
        });
    core.run(work).unwrap();
}

And here are the required dependencies.

[dependencies]
futures = "0.1"
hyper = "0.11"
tokio-core = "0.1"
Januson
  • 4,533
  • 34
  • 42
5

Try to go for reqwest:

extern crate reqwest;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut res = reqwest::get("https://httpbin.org/headers")?;

    // copy the response body directly to stdout
    std::io::copy(&mut res, &mut std::io::stdout())?;

    Ok(())
}
1

Be aware that hyper has lots of dependencies and reqwest not only depends on hyper but also brings quite a few additional dependencies. This may or may not be an issue for you, but it's something you should be aware of.

An alternative you might want to consider is minreq. That crate has only 1 dependency by default (the log crate) and a few more that depend on optional features. For example, if you activate the https-native feature, it will also add native-tls as a dependency.

at54321
  • 8,726
  • 26
  • 46