anterofit Build Status On Crates.io

Anterofit is a collection of Rust macros coupled to a lightweight, self-contained HTTP framework that allows you to create strongly-typed Rust wrappers around REST APIs with ease.

```rust // See examples/post_service.rs for more details

[macro_use] extern crate anterofit;

extern crate rustc_serialize;

use anterofit::{Adapter, Url};

[derive(Debug, RustcDecodable)]

struct Post { pub userid: Option, pub id: u64, pub title: String, pub body: String }

service! { trait PostService { /// Get a Post by id. fn get_post(&self, id: u64) -> Post { GET("/posts/{}", id) }

    /// Get all posts.
    fn get_posts(&self) -> Vec<Post> {
        GET("/posts")
    }

    /// Create a new Post under the given user ID with the given title and body.
    fn new_post(&self, userid: u64, title: &str, body: &str) -> Post {
        POST("/posts/");
        // We use the `EAGER:` keyword so we can use borrowed values in the body.
        // This serializes the body value immediately instead of waiting to serialize
        // it on the executor.
        body_map!(EAGER:
            "userid" => userid,
            "title": title,
            "body": body
        )
    }
}

}

fn main() { // Navigate to this URL in your browser for details. Very useful test API. let url = Url::parse("https://jsonplaceholder.typicode.com").unwrap();

let adapter = Adapter::builder()
    .base_url(url)
    // When your REST API uses JSON in both requests and responses
    .serialize_json()
    .build();

create_post(&adapter);
fetch_posts(&adapter);

}

/// Create a new Post. // All service traits are implemented for Adapter by default; using generics like this promotes good namespacing. fn createpost(postservice: &P) { let post = postservice.newpost(42, "Hello", "World!") // Execute the request in the background and wait for it to complete .exec().block() .unwrap();

println!("{:?}", post);

}

/// Fetch the top 3 posts in the database. // Service traits are object-safe by default fn fetchposts(postservice: &PostService) { let posts = postservice.getposts() // Shorthand for .exec().block(), but executes the request on the current thread. .exec_here() .unwrap();

for post in posts.into_iter().take(3) {
    println!("{:?}", post);
}

} ```

Inspired by Square's Retrofit, as referenced in the name, Anterofit is even more strongly typed as everything that is feasible to check at compile-time, is. Runtime errors are, with few exceptions, reserved for error conditions that can only be discovered at runtime.

Usage

Get started with our User Guide

Or an in-depth look with our Documentation

Setup

rustc-serialize:

Cargo.toml: toml [dependencies] anterofit = "0.1" rustc-serialize = "0.3"

Crate Root: ```rust

[macro_use] extern crate anterofit;

extern crate rustc_serialize;

```

Serde and JSON serialization:

Cargo.toml: ```toml [dependencies] serde = "0.8"

[dependencies.anterofit] version = "0.1" default-features = false features = ["serde", "serde_json"] ```

Then see Serde's Setting Up Codegen guide.

Choosing a serialization framework

rustc-serialize and Serde both have their pros and cons. Neither is a clear winner over the other; it depends entirely on your needs.

rustc-serialize Serde
Pros
  • #[derive] has been stable for a long time
  • (Potentially) Faster Compilation:
    • No Transitive Dependencies
    • Uses compiler datastructures / doesn't have to reparse
  • More/extensible serialization options
  • Likely more performant serialization
Cons
  • Likely less performant serialization
  • Still somewhat unstable (may go away or change forms)
  • (Useful) serialization limited to JSON
  • #[derive] only recently stabilized
  • Slower compilation:
    • Several transitive dependencies
    • Procedural macros currently have to reparse the token stream instead of reusing compiler datastructures

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.