#http #https #http-request #http-response #https-client #http-get

nano-get

A very tiny implementation of HTTP(s) GET, using minimal dependencies

4 releases

0.2.4 May 1, 2020
0.2.3 Jan 6, 2020
0.1.0 Dec 31, 2019

#1801 in Network programming

MIT license

36KB
506 lines

nano-get

Crates.io Docs.rs Rust

A minimalistic implementation of HTTP GET using only the standard library by default.

If you require https, please enable the "https" feature flag like:

nano-get = { version = "0.2.4", features = ["https"] }

Enabling the https flag, uses the rust openssl crate.

The OpenSSL Crate assumes that you have OpenSSL in your environment.

Please note that this may not be the best or most efficient implementation of the HTTP GET. The whole purpose is to have a basic functioning HTTP GET implementation and avoid having to import a gazzilion other packages, when all you want is a regular GET method for something simple.

More features might be added later, with the primary goal being to reduce the final binary size by not having too many dependencies other than this crate.

Currently the only other dependency is the openssl crate if you enable the "https" feature flag for this crate. The default use of this crate has zero external dependencies, other than the standard library.

Feature Flags

  • https : This enables https based on the Rust openssl crate

Example Usages

If all you care about is making a get request, then you can call the nano_get::get() method like below.

extern crate nano_get;
use nano_get::get;

fn main() {
    let response = get("http://dummy.restapiexample.com/api/v1/employees");
    println!("{}", response);
}

An example with the https feature flag enabled:

extern crate nano_get;
use nano_get::get;

fn main() {
    let response = get("https://google.com");
    println!("{}", response);
}

For more fine-grained control of the request/response, you can construct a request.

extern crate nano_get;
use nano_get::get;

fn main() {
    let mut request = Request::default_get_request("http://dummy.restapiexample.com/api/v1/employees").unwrap();
    request.add_header("test", "abracadabra");
    let response = request.execute().unwrap();
    println!("{}", response.status);
    println!("{}", response.body);
}

Models

The basic models in this crate are:

  • Url
  • Request
  • Response

Executing HTTP(s) Requests:

There are two ways to execute the HTTP(s) requests.

Basic Get

The basic version, demonstrated by the use of the nano_get::get function, which takes a url and returns the body of the response.

Example

extern crate nano_get;
use nano_get::get;

fn main() {
    let response = nano_get::get("https://www.google.com");
    println!("{}", response);
}

Request-Response based

Another more fine-grained method exists by using the nano_get::Request object. This gives you access to request headers, optional request body and the execution returns a nano_get::Response object. This allows inspection of HTTP Response codes, response body, etc.

Example

extern crate nano_get;
use nano_get::{Request, Response};

fn main() {
    let mut request = Request::default_get_request("http://example.com/").unwrap();
    let response: Response = request.execute().unwrap();
    println!("{}", response.body);
}

For details, check the Request and Response structure documentation.

Async:

As of writing this, this crate does not using async/await features of Rust. However, this does not stop the user from using this library in their application in a async context.

A dummy example is shown below. This uses the free REST API at jsonplaceholder to retreive 100 albums (100 HTTPS GET requests) concurrently using tokio/futures async/await utils.

This example is not a benchmark and only meant to demonstrate how to write an async wrapper around the crate's get method. This is also not meant to be demonstrative of idiomatic uses of the async libraries.

Cargo.toml snippet

[dependencies]
nano-get = {version = "0.2.4", features = ["https"] }
tokio = { version = "0.2.10", features = ["blocking", "rt-threaded"] }
futures = "0.3.1"

main.rs

extern crate futures;
extern crate nano_get;
extern crate tokio;

use std::time::Instant;

use tokio::runtime::{Runtime, Builder};
use futures::future::try_join_all;

fn main() {
    let mut runtime: Runtime = Builder::new().threaded_scheduler().build().unwrap();
    runtime.block_on(async {
        let base_url = "https://jsonplaceholder.typicode.com/albums";
        let mut handles = Vec::with_capacity(100);
        let start = Instant::now();
        for i in 1..=100 {
            let url = format!("{}/{}", base_url, i);
            handles.push(tokio::task::spawn_blocking(move || nano_get::get(url)));
        }
        let responses: Vec<String> = try_join_all(handles).await.unwrap();
        let duration = start.elapsed();
        println!("# : {}\n{}", responses.len(), responses.last().unwrap());
        println!("Time elapsed in http get is: {:?}", duration);
        println!("Average time for get is: {}s", duration.as_secs_f64() / (responses.len() as f64));
    });
}

example output

# : 100
{
  "userId": 10,
  "id": 100,
  "title": "enim repellat iste"
}
Time elapsed in http get is: 1.171043748s
Average time for get is: 0.01171043748s

Dependencies

~0–485KB
~11K SLoC