<div align="center">
<img src="https://pillan.inf.uct.cl/~lrevillod/images/sword-logo.webp" alt="Sword Logo" width="200">
<h1>โ๏ธ Sword โ๏ธ</h1>
<p><em>A prototype for a rust web framework</em></p>
---
> **๐ง Prototype Status**
>
> This is a **prototype** and **not production-ready**. It is intended for:
> - ๐ **Educational purposes**
> - ๐ฌ **Exploring web framework design**
> - ๐ ๏ธ **Axum wrapper experimentation**
>
> While it may scale well in the future, **it is not recommended for production use** at this stage.
---
</div>
## โจ Features
- ๐ฃ๏ธ **Macro-based routing** - Clean and intuitive route definitions
- ๐ **Complex query parameters** - Ready for advanced parameter handling
- ๐ **JSON-first design** - Built with JSON formats as priority
- โ
**Built-in validation** - Support with `serde` and `validator` crates
- ๐ **RFC-compliant HTTP responses** - Using `axum_responses` crate
- ๐ก **Express-Like** - It provides a `req` from request with some utility methods.
## ๐ ๏ธ Usage
### Basic web server
```rust
use sword::prelude::*;
#[controller("/")]
struct AppController {}
#[controller_impl]
impl AppController {
#[get("/")]
async fn get_data() -> HttpResponse {
let data = vec![
"This is a basic web server",
"It serves static data",
"You can extend it with more routes",
];
HttpResponse::Ok().data(data)
}
#[get("/hello")]
async fn hello() -> HttpResponse {
HttpResponse::Ok().data("Hello, World!")
}
#[post("/submit")]
async fn submit_data(req: Request) -> Result<HttpResponse> {
let body = req.body::<serde_json::Value>()?;
Ok(HttpResponse::Ok()
.data(body)
.message("Data submitted successfully"))
}
}
#[tokio::main]
async fn main() {
Application::builder()
.controller::<AppController>()
.run("0.0.0.0:8080")
.await;
}
```
### With Middleware
```rust
use serde_json::json;
use std::sync::{Arc, OnceLock};
use sword::prelude::*;
use tokio::sync::RwLock;
type InMemoryDb = Arc<RwLock<Vec<String>>>;
const IN_MEMORY_DB: OnceLock<InMemoryDb> = OnceLock::new();
fn db() -> Arc<RwLock<Vec<String>>> {
IN_MEMORY_DB
.get_or_init(|| Arc::new(RwLock::new(Vec::new())))
.clone()
}
#[derive(Clone)]
struct AppState {
db: InMemoryDb,
}
struct MyMiddleware;
impl MiddlewareWithState<AppState> for MyMiddleware {
async fn handle(ctx: State<AppState>, mut req: Request, next: Next) -> MiddlewareResult {
let count = ctx.db.read().await.len();
req.extensions.insert(count);
Ok(next.run(req.into()).await)
}
}
#[controller("/api")]
struct AppController {}
#[controller_impl]
impl AppController {
#[get("/data")]
#[middleware(MyMiddleware)]
async fn submit_data(state: State<AppState>, req: Request) -> HttpResponse {
let db = &state.db;
let count = req.extensions.get::<usize>().cloned().unwrap_or(0);
let message = format!("Current data count: {}", count);
db.write().await.push(message);
HttpResponse::Ok().data(json!({
"count": count,
"current_data": db.read().await.clone(),
}))
}
}
#[tokio::main]
async fn main() {
let app_state = AppState { db: db() };
Application::builder()
.state(app_state)
.controller::<AppController>()
.run("0.0.0.0:8080")
.await;
}
```
## Currently working on
- โ
๐ฑ Add Application struct
- โ
๐๏ธ Add Application Context
- โ
๐ Add Middleware support
- [ ] ๐ Add Dependency Injection support based on `shaku` crate
## ๐ Roadmap
- [ ] โ๏ธ Add config file support
- [ ] ๐ Add File - FormData support
- [ ] ๐งช Add more tests
- [ ] ๐ Add more documentation
- [ ] ๐ ๏ธ CLI Command line interface for code-generation (templates)