Crates.io | api |
lib.rs | api |
version | 0.2.0 |
source | src |
created_at | 2017-05-06 15:00:40.543465 |
updated_at | 2017-08-02 14:52:22.704919 |
description | abstraction for HTTP API clients |
homepage | https://github.com/hephex/api |
repository | https://github.com/hephex/api |
max_upload_size | |
id | 13376 |
size | 13,602 |
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::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 trait std::io::Read
.
If the endpoint doesn't require a body std::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
).