2 unstable releases
Uses old Rust 2015
0.2.0 | May 7, 2017 |
---|---|
0.1.0 | May 6, 2017 |
#503 in HTTP client
23 downloads per month
Used in bouncer
12KB
158 lines
api
api
provides a set of utilities for defining
HTTP API on the client side without worrying about
the actual HTTP client (until you send the
request!).
Api trait
api::Api
is a trait used to define a remote API.
The developer must implement it for the struct
that represents the API endpoint.
For our examples, we'll create a simple client for httpbin
and its endpoint /delay:n
(delays responding n seconds
and returns some information about the request).
Api
has three associated types:
-
Body
is used to generate the request body and it must implement the traitstd::io::Read
. If the endpoint doesn't require a bodystd::io::Empty
should be used. -
Reply
defines the response that we expect to receive from the API. -
Error
defines all the expected errors that we could get when the response is received.
First of all, we need to define the request and the response.
/delay/:n
has only one parameter in the path and we'll only care about the fields origin
and headers
in the JSON response
(we'll use serde_json
to parse the response's body).
extern crate api;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
// request for /delay/:n
struct Delay {
delay: u8
}
// it's a subset of the available data
#[derive(Deserialize)]
struct Info {
origin: String, // ip address
headers: BTreeMap<String, String>, // headers received by the server
}
impl api::Api for Delay {
type Reply = Info;
type Body = io::Empty;
type Error = serde_json::Error;
...
}
Then, we can start defining how the HTTP request will look like
implementing the trait Api
for Delay
.
We'll send a GET
request to /delay/:n
and :n
will be
replaced with the value in Delay.delay
.
impl api::Api for Delay {
type Reply = Info;
type Body = io::Empty;
type Error = serde_json::Error;
fn method(&self) -> api::Method {
api::Method::Get
}
fn path(&self) -> String {
// use a safe joiner to create the path!
format!("/delay/{}", self.delay)
}
fn query(&self) -> api::Query {
// we'll send any parameter in the query
Query::new()
}
fn headers(&self) -> api::Header {
let mut headers = api::Header::new();
headers.insert("X-Request-ID", "abcde");
headers
}
fn body(&self) -> std::io::Empty {
std::io::empty()
}
}
Now, we need to create the reply Info
from
the HTTP response represented by the trait HttpResponse
.
impl api::Api for Delay {
type Reply = Info;
type Body = io::Empty;
type Error = serde_json::Error;
...
fn parse<R: HttpResponse>(&self, resp: &mut R) -> Result<Info, serde_json::Error> {
serde_json::from_reader(resp.body())
}
}
api
has a trait Client
to create an adapter for the actual HTTP client, and it implements it for hyper::Client
.
Client
has a method send
that accepts the base URL for the API
and the request.
extern crate hyper;
use api::Client;
...
fn main() {
let mut client = hyper::Client::new();
let resp = client.send("http://httpbin.org/", Delay { delay: 1 });
println!("{:?}", resp);
}
The full code is in examples/httpbin.rs
(run cargo run --example=httpbin --features=use-hyper
).
Dependencies
~0–1MB
~19K SLoC