Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/target

docs/
docs/

# macOS
.DS_Store
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
[package]
name = "beckon"
version = "0.3.0"
version = "0.3.1"
edition = "2021"
rust-version = "1.75"
authors = ["Azeem Shaik <azeemshaik025@gmail.com>"]
description = "Generate type-safe, async HTTP clients from endpoint definitions — a Rust proc macro."
repository = "https://github.com/azeemshaik025/beckon"
Expand Down
39 changes: 22 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,24 @@ 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;

#[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!(
Expand Down Expand Up @@ -97,11 +99,14 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
- `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 <token>`
beckon!(GithubApi, auth: Bearer, { /* ... */ });
let client = GithubApi::new(url, "ghp_xxxx", Duration::from_secs(5));
Expand All @@ -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,
Expand Down Expand Up @@ -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));
```
Expand All @@ -165,7 +170,7 @@ Every method returns `Result<Res, UserApiError>`. 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 }) => {
Expand All @@ -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

Expand Down
48 changes: 1 addition & 47 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -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<User>,
//! },
//! {
//! path: "/users/{id}",
//! method: GET,
//! path_params: UserPath,
//! res: User,
//! }
//! }
//! );
//!
//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
//! 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;

Expand Down
Loading