Skip to content

bigoldcat123/graduation

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

168 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Faithea

License Rust Crates.io

A lightweight, high-performance asynchronous HTTP framework built with pure Rust. Supports both HTTP/1.1 and HTTP/2, providing powerful routing systems, WebSocket support, and flexible data extraction mechanisms.

✨ Features

  • πŸš€ Async High Performance - Built on Tokio for excellent concurrency
  • 🌐 Dual Protocol Support - HTTP/1.1 and HTTP/2 support
  • πŸ”Œ WebSocket Support - Built-in WebSocket server functionality
  • πŸ›‘οΈ Type Safety - Leverages Rust's type system for compile-time safety
  • 🎯 Flexible Routing - Exact match, parameterized paths, and wildcard routes
  • πŸ“¦ Smart Data Extraction - Automatic parsing for JSON, Multipart, query parameters, and path parameters
  • πŸ” Guard Middleware - Chainable request validation and authentication middleware
  • 🌍 CORS Support - Built-in Cross-Origin Resource Sharing support
  • πŸ”’ TLS/HTTPS - Complete encrypted connection support
  • ⚠️ Global Error Handling - Unified error handling mechanism

πŸ“¦ Project Structure

graduation/
β”œβ”€β”€ faithea/              # Core HTTP framework library
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ server/      # HTTP/1.1 and HTTP/2 server implementation
β”‚   β”‚   β”œβ”€β”€ handler/     # Request handler and routing system
β”‚   β”‚   β”œβ”€β”€ websocket/   # WebSocket implementation
β”‚   β”‚   β”œβ”€β”€ data/        # Data extraction and conversion (JSON, Multipart, etc.)
β”‚   β”‚   β”œβ”€β”€ guard/       # Middleware Guard system
β”‚   β”‚   β”œβ”€β”€ request/     # HTTP request parsing
β”‚   β”‚   β”œβ”€β”€ response/    # HTTP response building
β”‚   β”‚   └── route/       # Route pattern matching
β”‚   └── Cargo.toml
β”œβ”€β”€ faithea-macro/       # Procedural macro library (route decorators, etc.)
β”‚   └── Cargo.toml
β”œβ”€β”€ app/                 # Example application
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ main.rs      # Example server
β”‚   β”‚   β”œβ”€β”€ ws/          # WebSocket examples
β”‚   β”‚   └── util/        # Utility functions
β”‚   └── Cargo.toml
└── Cargo.toml           # Workspace configuration

πŸš€ Quick Start

Installation

Add this to your Cargo.toml:

[dependencies]
faithea = "0.1.8"
tokio = { version = "1.48.0", features = ["rt-multi-thread","macros"] }
serde = { version = "1.0", features = ["derive"] }

Your First Server

use faithea::{get, handlers, HttpServer, res_modifiers, response::cors::CORS};

#[get("/")]
async fn hello_world() {
    res_modifiers!("Hello, Faithea!", CORS)
}

#[tokio::main]
async fn main() {
    HttpServer::builder()
        .mount("/", handlers!(hello_world))
        .host("127.0.0.1")
        .port(8080)
        .build()
        .run()
        .await
        .unwrap();
}

Run the server:

cargo run

Visit http://127.0.0.1:8080/ to see the response!

πŸ“– Usage Guide

Route Definition

Define routes using macros:

use faithea::{get, post, put, delete, handlers};

#[get("/")]
async fn index() {
    "Welcome to Faithea!"
}

#[get("/users/{id}")]
async fn get_user(id: String) {
    format!("User ID: {}", id)
}

#[post("/users")]
async fn create_user() {
    "User created!"
}

#[tokio::main]
async fn main() {
    HttpServer::builder()
        .mount("/", handlers!(index, get_user, create_user))
        .host("127.0.0.1")
        .port(8080)
        .build()
        .run()
        .await
        .unwrap();
}

JSON Data Handling

use serde::{Deserialize, Serialize};
use faithea::{post, data::Json};

#[derive(Debug, Serialize, Deserialize)]
struct User {
    name: String,
    age: i32,
}

#[post("/users")]
async fn create_user(Json(user): Json<User>) -> Json<User> {
    Json(user)
}

Multipart File Upload

use faithea::{
    data::inbound::multipart::{MultiPartFile, Multipart},
    MultipartData, post,
};

#[derive(MultipartData)]
struct UploadData {
    pub username: String,
    pub profile: Vec<MultiPartFile>,
}

#[post("/upload")]
async fn upload(Multipart(data): Multipart<UploadData>) -> String {
    format!(
        "Uploaded {} files for user {}",
        data.profile.len(),
        data.username
    )
}

Query Parameters and Path Parameters

use faithea::{get, TryFromParam};

#[derive(Debug)]
struct Age {
    value: i32,
}

impl TryFromParam<'_> for Age {
    fn try_from_param(value: &String) -> Result<Self, HttpHandlerError> {
        Ok(Age {
            value: value.parse()?,
        })
    }
}

#[get("/search")]
async fn search(
    #[search_param] name: String,
    #[search_param] age: Option<String>
) -> String {
    format!("Searching for {}, age: {:?}", name, age)
}

#[get("/users/{id}")]
async fn get_user(id: String, age: Age) -> String {
    format!("User {}, age {}", id, age.value)
}

WebSocket Support

static WS_SENDERS: LazyLock<Mutex<HashMap<String, Sender<WebSocketDataPayLoad>>>> =
    LazyLock::new(|| Mutex::new(HashMap::new()));

#[derive(Serialize, Deserialize)]
struct WsDataMessage {
    r#type: String,
    to: String,
    from: String,
    content: String,
}

pub async fn ws(
    websocket: WebSocket,
    req: HttpRequest,
) {
    let  (mut r,s) = websocket.split();
    let name = req.get_pathparam("name").unwrap();
    {
        let mut map = WS_SENDERS.lock().await;
        map.insert(name.clone(), s.clone());
    }
    while let Some(msg) = r.recv().await {
        let data = serde_json::from_slice::<WsDataMessage>(msg.as_bytes()).unwrap();
        let map = WS_SENDERS.lock().await;
        if let Some(sender) = map.get(&data.to) {
            let a:String = serde_json::to_string(&data).unwrap();
            sender.send(WebSocketDataPayLoad::text(a)).await.unwrap();
        }
    }
}

// Register in main:
HttpServer::builder()
    .websocket("/ws/{name}", ws_handler)
    // ... other configurations

Middleware Guards

use faithea::HttpServer;

#[tokio::main]
async fn main() {
    HttpServer::builder()
        .guard("/api/**", async |req| {
            // Validate API key
            if req.headers().get("Authorization").is_some() {
                Ok(req)
            } else {
                Err(HttpResponse::unauthorized())
            }
        })
        .guard("/**", async |req| Ok(req))  // Allow all other requests
        .mount("/api", handlers!(api_handler))
        // ... other configurations
}

Global Error Handler

use faithea::HttpServer;

HttpServer::builder()
    .globale_error_handler(async |e: Error| {
        res_modifiers!(format!("Error: {:?}", e))
    })
    // ... other configurations

CORS and HTTPS

HttpServer::builder()
    .cors()  // Enable CORS
    .tls("key.pem", "cert.pem")  // Enable TLS
    .h2()  // Enable HTTP/2
    .port(443)
    // ... other configurations

πŸ”§ Tech Stack

  • Tokio - Async runtime
  • Serde - Serialization/deserialization
  • http - HTTP type definitions
  • rustls - TLS implementation
  • h2 - HTTP/2 implementation

πŸ“ Examples

Check the app/ directory for complete examples:

  • Basic Routing: Various route type demonstrations
  • Data Processing: JSON, Multipart, and other data format handling
  • WebSocket: Real-time communication examples
  • Middleware: Authentication and Guard examples

🀝 Contributing

Contributions are welcome! Please feel free to submit Issues or Pull Requests.

πŸ“„ License

This project is dual-licensed under MIT OR Apache-2.0. You can choose whichever license you prefer.


Made with ❀️ by the Faithea Team

About

graduation design

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors