DEV Community

Cover image for Exploring deboa-macros: Ergonomic HTTP Client Macros for Rust
Rogério Araújo
Rogério Araújo

Posted on

Exploring deboa-macros: Ergonomic HTTP Client Macros for Rust

What is deboa-macros?

deboa-macros is a procedural-macro crate for Rust that builds on top of the core HTTP client deboa. Its goal is to simplify common HTTP request patterns using expressive macros---turning verbose boilerplate into concise, type-safe code.

Where deboa provides low-level HTTP capabilities (HTTP/1 + HTTP/2, async runtimes like Tokio or Smol, etc.), deboa-macros layers ergonomic syntax on top so you can focus on logic instead of
request-building ceremony.


Why Macros? --- The Case for deboa-macros

Rust's procedural macros allow developers to run code at compile time to generate boilerplate, enforce patterns, and create domain-specific syntax.

For HTTP requests, much of the code is repetitive:

  • building the request
  • serializing bodies
  • deserializing responses
  • handling errors

deboa-macros addresses these pain points with:

  • Shorthand macros for common HTTP methods (get!, post!, put!, patch!, delete!, fetch!)
  • Compile-time type safety for request/response bodies (via Serde)
  • Async/await support
  • Declarative API client definitions using the #[bora] attribute macro

The result is a more pleasant, readable workflow---without sacrificing control or safety.


Key Features & API Overview

✔ Function-like Macros

deboa-macros provides macros corresponding to HTTP verbs:

  • get!
  • post!
  • put!
  • patch!
  • delete!
  • fetch! (generic method caller)

Each macro expands into an async HTTP call using deboa, with optional body and response type handling.

#[bora] Attribute Macro

The bora macro lets you define a high-level API client declaratively.

You describe:

  • the endpoints
  • their HTTP methods
  • input parameters
  • response bodies
  • serialization format

The macro generates a fully-typed client struct with async methods.

✔ Serialization Formats Supported

  • JSON
  • XML
  • MessagePack

All wired through Serde.


Example: GET Request Using get!

use deboa::Deboa;
use deboa_extras::http::serde::json::JsonBody;

#[derive(serde::Deserialize)]
struct Post {
    id: u32,
    title: String,
    body: String,
    userId: u32,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut client = Deboa::new();
    let post: Post = get!(
        "https://jsonplaceholder.typicode.com/posts/1",
        &mut client,
        JsonBody,
        Post
    );

    println!("Post title: {}", post.title);
    Ok(())
}
Enter fullscreen mode Exit fullscreen mode

Example: Declarative API Client with #[bora]

use deboa::errors::DeboaError;
use deboa_macros::bora;
use vamo::Vamo;

#[derive(Deserialize, Debug)]
pub struct Post {
    pub id: u32,
    pub title: String,
}

#[bora(
    api(
        get(name="get_by_id", path="/posts/<id:i32>", res_body=Post, format="json")
    )
)]
pub struct PostService;

#[tokio::main]
async fn main() -> Result<(), DeboaError> {
    let client = Vamo::new("https://jsonplaceholder.typicode.com");
    let mut service = PostService::new(client);

    let post = service.get_by_id(1).await?;
    println!("id: {}", post.id);
    println!("title: {}", post.title);

    Ok(())
}
Enter fullscreen mode Exit fullscreen mode

When to Use deboa-macros

Great Fit When:

  • You want concise, readable HTTP calls.
  • You prefer declarative API client definitions.
  • You care about type-safe request/response handling.
  • You're working with async Rust.

Consider Using Raw deboa When:

  • You need very fine-grained control over request lifecycle.
  • You need complex middleware or streaming.
  • You prefer explicit, hand-written code over macro-generated abstractions.

Ecosystem Fit

deboa-macros sits on top of a trio of crates:

  • deboa --- core HTTP client
  • deboa_extras --- additional serialization/compression helpers
  • deboa-macros --- ergonomic macros and declarative API definitions

This combination forms a flexible stack for building REST clients in Rust with minimal boilerplate.


My Take

As a developer, libraries that reduce boilerplate without hiding
important details are always welcome. deboa-macros hits that sweet spot:

  • It speeds up API client creation
  • It preserves strong typing
  • It works seamlessly with Rust async and Serde
  • You can still drop down to raw deboa for advanced behavior

If you're building internal tools, microservices, or interacting with REST APIs, deboa-macros is definitely worth trying.


Conclusion

deboa-macros brings ergonomic macros, type safety, and readability to HTTP client code in Rust. It builds on deboa's solid async foundation to provide high-level, expressive syntax ideal for REST-heavy applications.

If you enjoy clean, declarative Rust with less boilerplate---and still want full control when needed---this crate is a strong choice.

Top comments (0)