3 releases

new 0.1.7 Jan 16, 2025
0.1.6 Jan 16, 2025

#145 in HTTP client

Download history

127 downloads per month

Apache-2.0

22KB
121 lines

Hadorn

Crates.io Apache licensed Build Status

A type-safe HTTP client for Rust, inspire by retrofit.

Example

your Cargo.toml could look like this:

[dependencies]
hadorn = { version = "0.1" }
reqwest = { version = "0.12", features = ["json"] }

And then the code:


use hadorn::{get, hadorn};
use http::{HeaderMap, HeaderName, HeaderValue};
use reqwest::{Client, Result};
use serde::Deserialize;

#[hadorn(
    serialized = Json,
    deserialized = Json
)]
trait Crates {
    #[get(path = "/api/<version>/crates")]
    async fn list(
        #[path] version: &str,
        #[query] page: usize,
        #[query = "per_page"] page_size: usize,
        #[optional]
        #[query = "q"]
        keyword: &str,
    ) -> Result<QueryCrateRespond>;
}

#[derive(Debug, Deserialize)]
struct QueryCrateRespond {
    crates: Vec<Crate>,
    meta: Meta,
}

#[derive(Debug, Deserialize)]
struct Crate {
    id: String,
    created_at: String,
    default_version: String,
    description: String,
    documentation: Option<String>,
    homepage: Option<String>,
    downloads: u64,
}

#[derive(Debug, Deserialize)]
struct Meta {
    next_page: Option<String>,
    prev_page: Option<String>,
    total: u64,
}

#[tokio::test]
async fn call_list() {
    let client = CratesClient::new(Client::new())
        .with_base_url("https://crates.io")
        .with_default_headers(HeaderMap::from_iter([(
            HeaderName::from_static("user-agent"),
            HeaderValue::from_static("hadorn-rs"),
        )]));
    // https://crates.io/api/v1/crates?page=1&per_page=5&q=reqwest
    let respond = client.list("v1", 1, 5, Some("reqwest")).await;
    println!("{:?}", respond);
}

Macro

  • hadorn

    define a grouped apis clientserializeddeserialized.

    • client: generate the client struct name, default is the trait name append Client

    • serialized: the current trait all child apis default serialize type

      • Json => request.json(...)
      • Form => request.form(...)
      • Multipart => request.multipart(...)
      • no set => request.body(...)
    • deserialized: the current trait all child apis default deserialize type

      • Text => response.text()
      • Json => response.json()
      • Bytes => response.bytes()
      • Response => response
      • no set => ()
  • get | post | put | delete | head | option | trace

    define a http request methodpathheadersserializeddeserialzed.

    • path: request path /api/user/<id>, use the <...> define a variable, example: /api/user/<id> contains a variable id.
    • headers: request headers, examples: headers = [("content-type", "application/json")]
    • serialized: same of hadorn, priority is higher.
    • deserialized: same of hadorn, priority is higher.
  • #[path] | #[query] | #[header] | #[body]

    #[path]#[query]#[header] can set a literal to rename the argument name: #[path = "version"], if the request param name not equals arument name.

    #[body] mark the argument is request body argument, only appear once.

Notice

hadorn current only supported reqwest library, The support for other HTTP client libraries will be added subsequently.

License

This project is licensed under the Apache 2.0

Dependencies

~4–15MB
~191K SLoC