retrofit-rs 0.1.0

A type-safe, declarative HTTP client library for Rust with interceptors, inspired by Retrofit
Documentation

🔧 Retrofit-rs

Crates.io Documentation License: MIT

A type-safe, declarative HTTP client library for Rust, inspired by Java Retrofit.

✨ Features

  • 🎯 Declarative API - Define your API with simple macros
  • 🔒 Type-Safe - Compile-time type checking
  • Async/Await - Built on tokio for high performance
  • 🔄 Interceptors - Powerful middleware system
  • 📝 Auto Serialization - Automatic JSON handling with serde
  • 🛡️ Memory Safe - Leveraging Rust's ownership system

🚀 Quick Start

Add Retrofit-rs to your Cargo.toml:

[dependencies]
retrofit-rs = "0.1"
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }

Define your API:

use retrofit_rs::{api, get, Result};
use serde::Deserialize;

#[derive(Debug, Deserialize)]
struct User {
    id: u64,
    name: String,
}

#[api("https://api.github.com")]
trait GitHubApi {
    #[get("/users/{username}")]
    async fn get_user(&self, username: &str) -> Result<User>;
}

#[tokio::main]
async fn main() -> Result<()> {
    let api = GitHubApiClient::new()?;
    let user = api.get_user("octocat").await?;
    println!("{:#?}", user);
    Ok(())
}

💡 Examples

Basic Usage

use retrofit_rs::{Retrofit, Result};

let client = Retrofit::builder()
    .base_url("https://api.example.com")
    .build()?;

let request = client.get("/users/{id}")
    .path_param("id", "123");

let user: User = client.execute(request).await?;

Timeout Configuration

use std::time::Duration;

let client = Retrofit::builder()
    .base_url("https://api.example.com")
    .timeout(Duration::from_secs(60))          // Overall timeout (default: 30s)
    .connect_timeout(Duration::from_secs(10))  // Connection timeout (default: 10s)
    .build()?;

With Interceptors

use retrofit_rs::interceptors::{LoggingInterceptor, AuthInterceptor};

let client = Retrofit::builder()
    .base_url("https://api.example.com")
    .add_interceptor(LoggingInterceptor::body())
    .add_interceptor(AuthInterceptor::bearer("token"))
    .build()?;

Declarative API with CRUD Operations

use retrofit_rs::{api, get, post, put, delete, Body, Path, Query};

#[derive(Serialize, Deserialize)]
struct Book {
    id: u32,
    title: String,
    author: String,
}

#[api("http://localhost:3030")]
trait BookApi {
    #[get("/books")]
    async fn list_books(&self) -> Result<Vec<Book>>;

    #[get("/books/{id}")]
    async fn get_book(&self, id: Path<u32>) -> Result<Book>;

    #[post("/books")]
    async fn create_book(&self, book: Body<Book>) -> Result<Book>;

    #[put("/books/{id}")]
    async fn update_book(&self, id: Path<u32>, book: Body<Book>) -> Result<Book>;

    #[delete("/books/{id}")]
    async fn delete_book(&self, id: Path<u32>) -> Result<()>;
}

// Use the API
let client = retrofit_rs::Retrofit::builder()
    .base_url("http://localhost:3030")
    .build()?;
let api = BookApiClient::with_client(client);

// Create
let book = api.create_book(Body::new(new_book)).await?;

// Read
let book = api.get_book(Path::new(1)).await?;

// Update
let updated = api.update_book(Path::new(1), Body::new(book)).await?;

// Delete
api.delete_book(Path::new(1)).await?;

🎯 Run Examples

# Complete CRUD example with Book server and Retrofit-rs client
cargo run -p retrofit-rs-examples --example book_crud

# GitHub API with type wrappers
cargo run -p retrofit-rs-examples --example github

🔧 Built-in Interceptors

Logging Interceptor

use retrofit_rs::interceptors::LoggingInterceptor;

// Basic logging (method and URL)
.add_interceptor(LoggingInterceptor::basic())

// With headers
.add_interceptor(LoggingInterceptor::headers())

// Full logging (including body)
.add_interceptor(LoggingInterceptor::body())

Auth Interceptor

use retrofit_rs::interceptors::AuthInterceptor;

// Bearer token
.add_interceptor(AuthInterceptor::bearer("token"))

// Basic auth
.add_interceptor(AuthInterceptor::basic("user", "pass"))

// API Key
.add_interceptor(AuthInterceptor::api_key("X-API-Key", "key"))

Retry Interceptor

use retrofit_rs::interceptors::RetryInterceptor;
use std::time::Duration;

.add_interceptor(
    RetryInterceptor::new(3)
        .with_delay(Duration::from_secs(1))
)

🏗️ Architecture

retrofit-rs/
├── retrofit-rs           # Core library
│   ├── Client            # HTTP client
│   ├── Interceptors      # Middleware system
│   └── Builder           # Fluent API
│
└── retrofit-rs-macros    # Procedural macros
    ├── #[api]            # API definition
    └── #[get/post]       # HTTP methods

📈 Comparison

Feature Java Retrofit Retrofit-rs
API Style Annotations Macros ✨
Type Safety Runtime Compile-time
Async Callback/RxJava async/await
Performance JVM overhead Zero-cost
Memory Safety GC Ownership

🎓 Why "Retrofit-rs"?

Retrofit-rs brings the beloved Retrofit API design pattern to Rust, combining Java's proven declarative HTTP client approach with Rust's compile-time safety and zero-cost abstractions.

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📝 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Acknowledgments

Inspired by Square's Retrofit for Java.


Made with ❤️ and 🦀 by the Rust community