Crate anterofit [−] [src]
Wrap REST calls with Rust traits.
#[macro_use] extern crate anterofit; service! { /// Trait wrapping `myservice.com` API. pub trait MyService { /// Get the version of this API. fn api_version(&self) -> String { GET("/version") } /// Register a user with the API. fn register(&self, username: &str, password: &str) { POST("/register"); fields! { username, password } } } }
Important Types
Service Traits
Created with the service!{}
macro as shown above, service traits encompass the actual request
submission and response parsing. Each service trait is automatically implemented for
Adapter
, and is object-safe by default, so you can use generic bounds or trait object coercion
to narrow the scope:
fn print_api_version(service: &MyService) { // This completes synchronously, blocking until the request is complete. let api_version = service.api_version().exec_here().unwrap(); println!("API version: {}", api_version); } fn register_user<S: MyService>(service: &S, username: &str, password: &str) { // By default, this will complete asynchronously. service.register(username, password) // exec() queues the request on the executor, // and ignore() silences the `unused_result` lint for `Call`. .exec().ignore(); // This function returns immediately; all the work is done on the executor. }
For more details, see the service!{}
macro.
Adapter
Built via Adapter::builder()
, this is the starting point for all requests. It encompasses
five core components, and one very important property:
The
Executor
is responsible for taking prepared requests and executing them. Since Anterofit is primarily designed to be asynchronous, the executor should submit jobs to be completed in the background. Several executors are provided in theexecutor
module, but a sane default for low-volume asynchronous requests is provided automatically.The
Interceptor
is a non-essential but endlessly useful component which can modify request parameters before they are submitted. This currently encompasses modifying the request URL and adding or overwriting HTTP headers. If your app requires some sort of API key or authentication header, you can add an interceptor to your adapter to automatically include the appropriate credentials with each request:
use anterofit::{Adapter, Url}; use anterofit::net::intercept::AddHeader; use anterofit::net::header::{Headers, Authorization, Bearer}; let adapter = Adapter::builder() .base_url(Url::parse("https://myservice.com/api").unwrap()) .interceptor(AddHeader(Authorization ( Bearer { token: "asdf1234hjkl5678".to_string() } ))) .build();
Interceptor
is also implemented for closures of the kind Fn(&mut anterofit::net::request::RequestHead)
,
but common operations are implemented as types in the anterofit::net::intercept
module.
You can also chain interceptors together, or call box_interceptor()
to transform
it to Box<Interceptor>
if you need to name the full type of Adapter
.
The
Serializer
is responsible for taking a strongly typed request body and converting it to something that can be read into the HTTP stream, such as JSON or a raw byte sequence.Conversely, the
Deserializer
is responsible for taking a response body in some predetermined format, such as JSON or XML, and reading out a strongly typed value.
If you just want JSON serialization and deserialization and don't care about the details,
use the serialize_json()
method of your adapter builder to set the serializer and deserializer
simultaneously.
The
Client
(hyper::client::Client
) is responsible for managing proxies, DNS resolution, and bootstrapping connections. A default instance will be constructed automatically if one is not provided, but you can configure your own instance to tweak some low-level stuff like timeouts or to use a particular proxy.Finally, the
base_url
, if provided, is automatically prepended to every request URL. This would generally be the protocol, domain and perhaps a path prefix, while request URLs can be standalone paths. That way you can easily swap between, for example, testing and production endpoints implementing the same REST API:
use anterofit::{Adapter, Url}; let adapter = Adapter::builder() .base_url(Url::parse("https://test.myservice.com/api").unwrap()) .build(); print_api_version(&adapter); register_user(&adapter, "username", "password"); let adapter = Adapter::builder() .base_url(Url::parse("https://prod.myservice.com/api").unwrap()) .build(); print_api_version(&adapter); register_user(&adapter, "username", "password");
Request
This type wraps the return value of every service trait method. Unlike in Retrofit,
where the request is determined to
be synchronous or asynchronous at the service method declaration site1, Request
gives the power
over this choice to the caller so that no change to the trait is needed to change the execution
context:
fn print_api_version(service: &MyService) { service.api_version() // This closure will be called with the `String` value on the executor .on_complete(|api_version| println!("API version: {}", api_version)) // We don't care about the result since it's `()` anyway. .exec().ignore(); }
1 : Retrofit v1 established synchronicity at the declaration site; v2 follows the same pattern as Anterofit, but the two were developed independently.
Call
Returned by Request::exec()
, this type is a pollable Future
which will yield the result
of the request when it is ready. If there was an error in constructing the request,
the result will be available immediately. Call
provides alternative methods wrapping
Future::poll()
and Future::wait()
without external types so you
have a choice over whether you want to use futures in your app or not.
Reexports
pub extern crate hyper; |
pub use error::Error; |
pub use net::body::RawBody; |
pub use net::request::Request; |
Modules
error |
Assorted error types and helper functions used by this crate. |
executor |
Types which can take a boxed closure and execute it, preferably in the background. |
mime |
Shorthands for various MIME types. |
net |
Anterofit's HTTP client framework, built on Hyper. |
serialize |
Types used to serialize and deserialize request and response bodies, respectively. |
Macros
body |
Serialize the given value as the request body. |
body_map |
Serialize a series of key-value pairs as the request body. |
fields |
Serialize a series of fields as the request body (form-encode them). |
map_builder |
Use in a service method body to perform an arbitrary transformation on the builder. |
meta_service |
Create a meta-service trait which combines the listed service traits. |
path |
A field value that resolves to a path on the filesystem. |
query |
Append a series of query pairs to the URL of the request. |
service |
Define a service trait whose methods make HTTP requests. |
stream |
A field value for anything that is |
with_builder |
Use in a service body to access the builder without consuming it. |
Structs
Adapter |
The starting point of all Anterofit requests. |
Url |
A parsed URL record. |
Traits
AbsAdapter |
Implemented by |
Type Definitions
JsonAdapter |
A shorthand for an adapter with JSON serialization enabled. |
Result |
The result type for this crate; used frequently in public APIs. |