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 the executor 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; they will be called in declaration order.

  • 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).

force_body

Allows the inside expression to set a body on a request which doesn't regularly take one.

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 Read + Send + 'static.

unsizeable

Create an implementation of UnsizeService for the given service trait.

with_builder

Use in a service body to access the builder without consuming it.

Structs

Adapter

The starting point of all Anterofit requests.

AdapterBuilder

A builder for Adapter. Call Adapter::builder() to get an instance.

InterceptorMut

A mutator for modifying the Interceptor of an Adapter.

Url

A parsed URL record.

Traits

AbsAdapter

Used by Anterofit's various APIs.

UnsizeService

Unsizeable service trait. Used with Adapter::arc_service().

Type Definitions

JsonAdapter

A shorthand for an adapter with JSON serialization enabled.

Result

The result type for this crate; used frequently in public APIs.