From 31e74af04ce8e701affd76368fe1376eafc3881a Mon Sep 17 00:00:00 2001 From: Azeem Shaik Date: Sun, 9 Aug 2026 12:02:02 +0530 Subject: [PATCH 1/3] Release 0.3.1: sync docs.rs with the README, declare MSRV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docs and metadata only — no code or behavior changes. - Crate-level docs are now sourced from the README via `#![doc = include_str!("../README.md")]`, so docs.rs and crates.io no longer drift. Previously docs.rs showed only the basic example while auth, retries, with_client, and error handling lived only in the README. README `rust` fences are annotated (`no_run` / `ignore`) so doctests still compile-verify the API. - Declared `rust-version = "1.75"` (the generated trait uses async fn in traits). - README: documented the method-naming rule; example links are now absolute so they resolve on crates.io and docs.rs. --- .DS_Store | Bin 0 -> 6148 bytes CHANGELOG.md | 17 +++++++++++++++++ Cargo.lock | 2 +- Cargo.toml | 3 ++- README.md | 29 +++++++++++++++++------------ src/lib.rs | 48 +----------------------------------------------- 6 files changed, 38 insertions(+), 61 deletions(-) create mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..eb4c51d9343906ec00824064e93c10ceca6853bc GIT binary patch literal 6148 zcmeHLyH3L}6uqVas#Zu9FfcG=Lp+4&!b+&Z7j$ESrd5m7C{-W8g2)2jfcOBugOLS^ zmASAp!2kotk2ZGGc0{Q1mF(mAUfU)>I3hJ`C^N02A)u%(# zU!Cf2HMG4UzlWx@I2e~2)T4?qIrf7s+|bV;Wa zQj3}>cT7eHOJJ0W(K&qvZy%ddmoae(t7&m2FR_(os6%ZEOg7iYV52-bhn=tc?=8t; z=uJjWd(H7)&?zlY7b>)|CThl-V8xrDHtN^MzFYa(Q0v0zL!XgJF&YoHeo@e$hi=sZT6dBd5_Et{8UbE|+=z$!3QfbS135=T#A zEKzJ7$ix)@=%88{$^~8kx(Ypou|#-aOg06|rc7Nim~4)ESH*b>V~MgkF?IQ1YGkHv zC`^ow{#_AH%#&zytAJI&R3IZC3;g^)ntcB^8`&qTfK_0o6kv{D_Dgsrb+)Enj-RzI u(g_kb9v4d#O^~VMSQPkC%>P#q2A|6dKu=*T5j8OTLqN!2GpoR#D)0-F`N8=B literal 0 HcmV?d00001 diff --git a/CHANGELOG.md b/CHANGELOG.md index 3feb060..7fccd69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,23 @@ All notable changes to this project are documented here. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.3.1] + +Documentation and metadata only — no code or behavior changes. + +### Documentation + +- The crate-level docs (docs.rs) are now sourced from the README via + `#![doc = include_str!("../README.md")]`, so docs.rs and crates.io no longer drift — + auth, retries, `with_client`, and error handling are all documented in both places. +- README: documented the method-naming rule, and example links are now absolute so they + resolve on crates.io and docs.rs. + +### Changed + +- Declared the minimum supported Rust version: `rust-version = "1.75"` (the generated + mocking trait uses `async fn` in traits). This was already required; it is now explicit. + ## [0.3.0] This release contains breaking changes to the constructor signature and the generated diff --git a/Cargo.lock b/Cargo.lock index 5961e6c..c0dd27c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,7 +41,7 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "beckon" -version = "0.3.0" +version = "0.3.1" dependencies = [ "heck", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index 1199d5a..e5834b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,8 @@ [package] name = "beckon" -version = "0.3.0" +version = "0.3.1" edition = "2021" +rust-version = "1.75" authors = ["Azeem Shaik "] description = "Generate type-safe, async HTTP clients from endpoint definitions — a Rust proc macro." repository = "https://github.com/azeemshaik025/beckon" diff --git a/README.md b/README.md index 892aff6..d4da3d9 100644 --- a/README.md +++ b/README.md @@ -25,9 +25,11 @@ cargo add serde --features derive cargo add tokio --features full ``` +Requires **Rust 1.75+** — the generated mocking trait uses `async fn` in traits. + ## Example -```rust +```rust,no_run use beckon::beckon; use serde::{Deserialize, Serialize}; use std::time::Duration; @@ -97,11 +99,14 @@ async fn main() -> Result<(), Box> { - `fn_name`: Custom method name - `retries`: Retry count for this endpoint (overrides the global setting) +Method names are derived from the method and path — `GET /users` → `get_users`, +`GET /users/{id}` → `get_users_by_id`. Set `fn_name` to override. + ## Auth Add automatic authentication to every request. Three strategies are supported: -```rust +```rust,ignore // Bearer token — injects `Authorization: Bearer ` beckon!(GithubApi, auth: Bearer, { /* ... */ }); let client = GithubApi::new(url, "ghp_xxxx", Duration::from_secs(5)); @@ -124,7 +129,7 @@ Set a global retry count that applies to all endpoints. Retries use exponential (100ms base, 2x multiplier, 5s cap) and trigger on 5xx errors and request timeouts. 4xx errors are never retried. -```rust +```rust,ignore beckon!( UserApi, retries: 3, @@ -154,7 +159,7 @@ Per-endpoint `retries` overrides the global value. Omitting `retries` entirely m `timeout` accepts a `std::time::Duration`, or `None` for the 5-second default. -```rust +```rust,ignore let http = reqwest::Client::builder().user_agent("my-app/1.0").build()?; let client = UserApi::with_client(url, http, Duration::from_secs(5)); ``` @@ -165,7 +170,7 @@ Every method returns `Result`. On a non-2xx response you get `Http` variant, which carries the server's response body so you can see *why* a request was rejected: -```rust +```rust,ignore match client.get_users_by_id(&UserPath { id: 999 }).await { Ok(user) => { /* ... */ } Err(UserApiError::Http { status, reason, body }) => { @@ -188,14 +193,14 @@ For a client named `UserApi`, the macro generates: ## Examples -See the [`examples/`](examples/) directory: +See the [`examples/`](https://github.com/azeemshaik025/beckon/tree/main/examples) directory: -- [`basic.rs`](examples/basic.rs) — simple GET requests -- [`params.rs`](examples/params.rs) — path and query parameters -- [`advanced.rs`](examples/advanced.rs) — all features -- [`mocking.rs`](examples/mocking.rs) — testing with the generated trait -- [`multiple_path_params.rs`](examples/multiple_path_params.rs) — nested resources -- [`error_handling.rs`](examples/error_handling.rs) — inspecting a failed request's body +- [`basic.rs`](https://github.com/azeemshaik025/beckon/blob/main/examples/basic.rs) — simple GET requests +- [`params.rs`](https://github.com/azeemshaik025/beckon/blob/main/examples/params.rs) — path and query parameters +- [`advanced.rs`](https://github.com/azeemshaik025/beckon/blob/main/examples/advanced.rs) — all features +- [`mocking.rs`](https://github.com/azeemshaik025/beckon/blob/main/examples/mocking.rs) — testing with the generated trait +- [`multiple_path_params.rs`](https://github.com/azeemshaik025/beckon/blob/main/examples/multiple_path_params.rs) — nested resources +- [`error_handling.rs`](https://github.com/azeemshaik025/beckon/blob/main/examples/error_handling.rs) — inspecting a failed request's body ## License diff --git a/src/lib.rs b/src/lib.rs index b5b43cb..ef94292 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,50 +1,4 @@ -//! Generate type-safe, async HTTP clients from endpoint definitions. -//! -//! `beckon!` takes a client name and a list of endpoints and expands to a struct -//! with one async method per endpoint, a matching trait for mocking, and a typed -//! error enum. -//! -//! ``` -//! use beckon::beckon; -//! use serde::{Deserialize, Serialize}; -//! use std::time::Duration; -//! -//! #[derive(Serialize, Deserialize)] -//! pub struct User { -//! pub id: u32, -//! pub name: String, -//! } -//! -//! #[derive(Serialize)] -//! pub struct UserPath { -//! pub id: u32, -//! } -//! -//! beckon!( -//! UserApi, -//! { -//! { -//! path: "/users", -//! method: GET, -//! res: Vec, -//! }, -//! { -//! path: "/users/{id}", -//! method: GET, -//! path_params: UserPath, -//! res: User, -//! } -//! } -//! ); -//! -//! # async fn example() -> Result<(), Box> { -//! let client = UserApi::new(reqwest::Url::parse("https://api.example.com")?, Duration::from_secs(5)); -//! let _users = client.get_users().await?; -//! let _user = client.get_users_by_id(&UserPath { id: 1 }).await?; -//! # Ok(()) -//! # } -//! # fn main() {} -//! ``` +#![doc = include_str!("../README.md")] extern crate proc_macro; From 449d19952c6aaa821721086f3a7537283afc0d9d Mon Sep 17 00:00:00 2001 From: Azeem Shaik Date: Sun, 9 Aug 2026 12:07:43 +0530 Subject: [PATCH 2/3] Fix doctest E0446: make README example types pub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The README example (now the crate docs via include_str!) declared private structs that the generated pub trait leaks, which stable rustc rejects with E0446. Local 1.92 only warned; CI stable (1.97) errors. Make User/UserPath pub — a public generated trait genuinely requires public response types. Verified with +stable. --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d4da3d9..b632175 100644 --- a/README.md +++ b/README.md @@ -35,14 +35,14 @@ use serde::{Deserialize, Serialize}; use std::time::Duration; #[derive(Serialize, Deserialize)] -struct User { - id: u32, - name: String, +pub struct User { + pub id: u32, + pub name: String, } #[derive(Serialize)] -struct UserPath { - id: u32, +pub struct UserPath { + pub id: u32, } beckon!( From 7ea44ebbf0d8eda05de717d452defee4cce29e9d Mon Sep 17 00:00:00 2001 From: Azeem Shaik Date: Sun, 9 Aug 2026 12:12:14 +0530 Subject: [PATCH 3/3] Remove accidentally-committed .DS_Store and gitignore it A stray git add -A on this branch swept up the macOS .DS_Store. Untrack it and add it to .gitignore so it can't recur. --- .DS_Store | Bin 6148 -> 0 bytes .gitignore | 5 ++++- 2 files changed, 4 insertions(+), 1 deletion(-) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index eb4c51d9343906ec00824064e93c10ceca6853bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHLyH3L}6uqVas#Zu9FfcG=Lp+4&!b+&Z7j$ESrd5m7C{-W8g2)2jfcOBugOLS^ zmASAp!2kotk2ZGGc0{Q1mF(mAUfU)>I3hJ`C^N02A)u%(# zU!Cf2HMG4UzlWx@I2e~2)T4?qIrf7s+|bV;Wa zQj3}>cT7eHOJJ0W(K&qvZy%ddmoae(t7&m2FR_(os6%ZEOg7iYV52-bhn=tc?=8t; z=uJjWd(H7)&?zlY7b>)|CThl-V8xrDHtN^MzFYa(Q0v0zL!XgJF&YoHeo@e$hi=sZT6dBd5_Et{8UbE|+=z$!3QfbS135=T#A zEKzJ7$ix)@=%88{$^~8kx(Ypou|#-aOg06|rc7Nim~4)ESH*b>V~MgkF?IQ1YGkHv zC`^ow{#_AH%#&zytAJI&R3IZC3;g^)ntcB^8`&qTfK_0o6kv{D_Dgsrb+)Enj-RzI u(g_kb9v4d#O^~VMSQPkC%>P#q2A|6dKu=*T5j8OTLqN!2GpoR#D)0-F`N8=B diff --git a/.gitignore b/.gitignore index 06fdf26..1c7e1db 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ /target -docs/ \ No newline at end of file +docs/ + +# macOS +.DS_Store \ No newline at end of file