| Crates.io | afast-macros |
| lib.rs | afast-macros |
| version | 0.0.13 |
| created_at | 2025-11-05 05:06:42.949081+00 |
| updated_at | 2025-12-04 06:32:06.060524+00 |
| description | AFast: high-performance async Rust web framework with HTTP, WS, TCP support, automatic client generation, validation, and documentation. |
| homepage | https://github.com/ahriroot/afast |
| repository | https://github.com/ahriroot/afast |
| max_upload_size | |
| id | 1917437 |
| size | 81,951 |
AFast is a high-performance asynchronous Rust backend framework designed to simplify building networked applications. It supports multiple protocols via feature flags and provides automatic code generation for clients (TypeScript and JavaScript), API documentation, and field validation.
You can enable the following features in your Cargo.toml:
http - enable HTTP support
/ - Document path (feature flag doc)/api - HTTP API endpoints/code/{service}/{lang} - Client code (feature flag js|ts ...)/doc - Service list (feature flag doc)/doc/{service} - Handler defintions and documentation (feature flag doc)ws - enable WebSocket support
/ws - WebSocket endpointtcp - enable TCP supportdoc - enable API documentation generationjs - enable JavaScript client generation (auto enabled code)ts - enable TypeScript client generation (auto enabled code)code - enable code generationNote on TCP usage:
If the tcp feature is enabled, the AFast::serve method takes two arguments:
"127.0.0.1:8080")."127.0.0.1:8081") for web clients and generated JS/TS clients.This allows you to run TCP and HTTP/WS servers simultaneously in the same application.
handler Macro: Declare HTTP endpoints with minimal boilerplate
ns("api.v1.user"))desc("Get user info"))The #[handler] attribute macro transforms async functions into full-featured API endpoints:
#[handler(desc("Get user information"), ns("api.v1.user"))]
async fn get_user(state: String, header: Header, req: Request) -> Result<Response, Error> {
// Your business logic
}
Macro Parameters:
desc("description") - API description for documentationns("api.v1.user") - Namespace for nested JS client generationGenerated Output:
use afast::{AFast, AFastData, AFastKind, Error, handler, middleware, register};
#[derive(Debug, Clone, AFastData, AFastKind)]
enum Sex {
Male,
Female,
Other(#[validate(desc("Other sex id"))] i64),
Custom {
#[validate(desc("Custom sex name"))]
name: String,
},
}
#[derive(Debug, Clone, AFastData, AFastKind)]
struct Request {
#[validate(desc("User ID"))]
id: i64,
#[validate(desc("User name"))]
name: String,
#[validate(
desc("User age"),
required("age is required"),
min(1, "age must be at least 1"),
max(256, "age must be at most 256")
)]
age: u32,
#[validate(desc("User hobbies"))]
hobbies: Vec<Hobby>,
#[validate(desc("User tags"))]
tags: Vec<String>,
#[validate(desc("User gender"))]
superuser: Option<bool>,
#[validate(desc("User sex"))]
sex: Sex,
#[validate(desc("User number"))]
number: f64,
}
#[derive(Debug, Clone, AFastData, AFastKind)]
struct Hobby {
id: i64,
name: String,
}
#[derive(Debug, AFastData, AFastKind)]
pub struct Response {
sex: Sex,
id: i64,
name: String,
age: u32,
hobbies: Vec<Hobby>,
tags: Vec<String>,
superuser: Option<bool>,
}
#[handler(desc("Get user information"), ns("api.user"))]
async fn get_user(_state: String, _header: Header, req: Request) -> Result<Response, Error> {
Ok(Response {
id: req.id,
name: req.name.clone(),
age: req.age,
hobbies: req.hobbies.clone(),
tags: req.tags.clone(),
superuser: req.superuser,
sex: req.sex.clone(),
})
}
#[derive(Debug, AFastData, AFastKind)]
struct Req2 {
id: i64,
}
#[derive(Debug, AFastData, AFastKind)]
struct Resp2 {
id: i64,
name: String,
}
#[handler(desc("Get user by id"), ns("api"))]
async fn get_id(_state: String, _header: Header, req: Req2) -> Result<Resp2, Error> {
Ok(Resp2 {
id: req.id,
name: "John".to_string(),
})
}
#[derive(Debug, Clone, AFastData, AFastKind)]
struct Header {
token: String,
}
#[middleware]
async fn auth(_state: String, header: Header) -> Result<Header, Error> {
println!("Token: {:?}", header);
Ok(header)
}
#[tokio::main]
async fn main() {
let state = "".to_string();
let server = AFast::<String, Header>::new(state)
.service("user", "User service", register! { get_user, get_id })
.middleware(auth);
server
.serve(
#[cfg(feature = "tcp")]
&"127.0.0.1:8080",
#[cfg(any(feature = "http", feature = "ws"))]
&"127.0.0.1:8081",
)
.await
.unwrap();
}