| Crates.io | awpak-rs |
| lib.rs | awpak-rs |
| version | 0.0.1 |
| created_at | 2025-02-27 23:12:15.744355+00 |
| updated_at | 2025-02-27 23:12:15.744355+00 |
| description | A lightweight web framework for Rust, built on top of Tokio and Hyper. |
| homepage | https://github.com/afuentesan/awpak-rs |
| repository | https://github.com/afuentesan/awpak-rs |
| max_upload_size | |
| id | 1572265 |
| size | 142,359 |
awpak-rs is a lightweight web framework for Rust, built on top of tokio and hyper. It simplifies request handling, middleware processing, and response generation, using declarative macros for a more ergonomic development experience.
⚠️ This is an initial version of the project, and the API may change in future releases.
#[get], #[post], #[put], #[delete], and more.serde.multipart/form-data file uploads efficiently.To use awpak-rs, add it to your Cargo.toml:
[dependencies]
awpak-rs = "0.0.1"
serde = { version = "1.0", features = ["derive"] }
use awpak_rs::*;
use serde::{Serialize, Deserialize};
#[awpak_main(ip = "127.0.0.1", port = "3001")]
fn main() {}
#[derive(Serialize, Deserialize, FromValue)]
struct Point {
x: Option<f32>,
y: f32,
}
#[get(url = "/get_point")]
fn get_point(#[query_params] point: Point) -> Point {
point
}
Run the server and test with:
curl "http://127.0.0.1:3001/get_point?x=1&y=2"
Response:
{"x":1.0,"y":2.0}
The #[awpak_main] macro defines the entry point of the application:
#[awpak_main(ip = "127.0.0.1", port = "3001")]
fn main() {}
ip (optional): The IP address to bind to (default: 127.0.0.1).port (optional): The port the server will listen on (default: 3000).Endpoints are defined using route macros such as #[get] and #[post]:
#[get(url = "/hello")]
fn hello() -> &'static str {
"Hello, world!"
}
#[get(url = "/greet")]
fn greet(
#[query_param] name: String
) -> String {
format!("Hello, {}!", name)
}
#[get(url = "/user/{id}")]
fn get_user(
#[path_variable] id: usize
) -> String {
format!("User ID: {}", id)
}
#[get(url = "/user/{id}")]
async fn get_user(#[path_variable] user: User) -> User {
user
}
impl FromAsyncStr<User> for User {
async fn from_async_str(io: &IO, s: &str) -> Result<User, ()> {
let user = get_user_from_db(s).await;
Ok(user)
}
}
Extract request headers:
#[post(url = "/header-example")]
fn header_example(
#[request_headers] headers: Headers
) -> String {
match headers.get_value("content-type") {
Some(content_type) => content_type,
None => "Content-Type not found".to_string(),
}
}
Modify response headers:
#[post(url = "/set-header")]
fn set_header(
#[response_headers] mut headers: Headers
) -> String {
headers.replace_header("content-type", "application/json");
"Header set".to_string()
}
Retrieve request cookies:
#[get(url = "/get-cookie")]
fn get_cookie(
#[request_cookies] cookies: Cookies
) -> String {
match cookies.find_first_by_name("session_id") {
Some(cookie) => format!("Session ID: {}", cookie.value()),
None => "No session cookie found".to_string(),
}
}
Modify response cookies:
#[post(url = "/set-cookie")]
fn set_cookie(
#[response_cookies] mut res_cookies: Cookies
) -> String {
res_cookies.add_cookie("user_id=12345; Path=/;").unwrap();
"Cookie set successfully".to_string()
}
Middlewares allow modifying incoming requests, responses, or setting shared context before or after executing an endpoint. They can:
#[middleware]
fn log_requests(mut io: IO) -> MiddlewareResponse {
println!("Received request: {} {}", io.request.method, io.request.uri.path);
MiddlewareResponse::Next(io)
}
Middlewares return:
MiddlewareResponse::Next(io): Continue to the next middleware or endpoint.MiddlewareResponse::Cancel(io): Stop execution and return a response immediately.Middleware can set shared context using IO::set_context:
struct ContextExample {
value: usize,
}
#[middleware]
fn set_context(mut io: IO) -> MiddlewareResponse {
io.set_context(ContextExample { value: 42 });
MiddlewareResponse::Next(io)
}
Endpoints can then retrieve this context:
#[get(url = "/context")]
fn get_context(
#[context] ctx: Option<&ContextExample>
) -> String {
match ctx {
Some(c) => format!("Context value: {}", c.value),
None => "No context available".to_string(),
}
}
Extract a single uploaded file:
#[post(url = "/upload")]
fn upload_file(
#[part_file] file: FileData
) -> usize {
file.bytes.len()
}
Extract multiple uploaded files:
#[post(url = "/upload-multiple")]
fn upload_multiple_files(
#[part_files] files: Vec<FileData>
) -> usize {
files.iter().map(|f| f.bytes.len()).sum()
}
Awpak-rs supports the following HTTP methods:
#[get]#[post]#[put]#[delete]#[patch]#[head]#[options]#[trace]#[connect]Awpak-rs is released under the MIT License.