nimble-http 1.0.0

A web framework
Documentation

Nimble

一个简单优雅的 Rust Web 框架,灵感来自 Express,基于 Hyper。

特性

  • 简单直观 - 类似 Express 的路由定义方式
  • 🚀 基于 Hyper - 建立在可靠的 HTTP 库之上
  • 📦 零成本抽象 - 使用 Rust 的强大类型系统
  • 🎯 类型安全 - 编译时确保路由和处理器的类型正确
  • 🔧 实用功能 - 内置 JSON、HTML、文件服务、重定向等响应类型
  • 📁 自动静态文件服务 - 自动挂载 ./static 目录下的文件

快速开始

Cargo.toml 中添加依赖:

[dependencies]
nimble = { git = "https://github.com/yourusername/nimble" }
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }  # 如果需要处理 JSON

创建一个简单的 Web 应用:

use nimble::{Router, get, post, post_json, Html, Json, Redirect, Text};
use serde::Deserialize;

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

#[tokio::main]
async fn main() {
    let app = Router::new()
        // GET 根路径,返回 HTML
        .route("/", get(|_| async {
            Html("<h1>Hello World</h1>".to_string())
        }))
        // GET 返回 JSON
        .route("/json", get(|_| async {
            Json(vec!["苹果", "香蕉", "橙子"])
        }))
        // POST 处理表单(application/x-www-form-urlencoded)
        .route("/user", post(|params| async move {
            let name = params.get("name").unwrap_or(&"匿名".to_string()).clone();
            Text(format!("Hello, {}!", name))
        }))
        // POST 处理 JSON
        .route("/api/user", post_json(|user: User| async move {
            Json(format!("创建用户: {},年龄: {}", user.name, user.age))
        }))
        // 重定向到百度
        .route("/baidu", get(|_| async {
            Redirect("https://www.baidu.com".to_string())
        }));

    // 启动服务器
    app.run("127.0.0.1", 3000).await;
}

路由

Nimble 目前支持 GETPOST 方法,其中 POST 又分为普通表单和 JSON 两种形式。

use nimble::{get, post, post_json};

Router::new()
    .route("/", get(handler_get))
    .route("/submit", post(handler_post))
    .route("/api/data", post_json(handler_post_json));

注意:当前版本不支持路径参数(如 /users/:id),也不支持 PUTDELETE 等方法。

响应类型

Nimble 提供了多种内置响应类型,均实现了 IntoResponse trait:

use nimble::{Html, Json, Text, Redirect, File, StatusCode};

// HTML 响应
Html("<h1>标题</h1>".to_string())

// JSON 响应(要求类型实现 Serialize)
Json(vec!["苹果", "香蕉", "橙子"])

// 纯文本响应
Text("Hello".to_string())

// 临时重定向 (302)
Redirect("https://example.com".to_string())

// 永久重定向 (301)
Redirect::perm("https://example.com".to_string())

// 文件响应(第一个参数为文件路径,第二个为是否强制下载)
File("static/image.jpg".to_string(), false)   // 直接显示
File("file.zip".to_string(), true)            // 作为附件下载

// 仅状态码(空响应)
StatusCode::NOT_FOUND

此外,以下类型也自动实现了 IntoResponse

  • &'static str
  • String
  • Vec<u8>
  • ()
  • Result<T, E> 其中 TE 都实现了 IntoResponse

静态文件服务

Router::new() 会自动扫描项目根目录下的 ./static 文件夹,并将所有文件映射为路由。

例如,目录结构如下:

├── static/
│   ├── css/
│   │   └── style.css
│   ├── js/
│   │   └── app.js
│   └── images/
│       └── logo.png
└── src/
    └── main.rs

启动应用后,可通过以下 URL 访问:

  • http://localhost:3000/css/style.css
  • http://localhost:3000/js/app.js
  • http://localhost:3000/images/logo.png

文件下载

静态文件路由支持通过查询参数 ?download=true 强制下载:

http://localhost:3000/images/logo.png?download=true

请求参数

GET 请求

GET 处理函数接收一个 HashMap<String, String>,包含 URL 查询字符串中的参数。

use std::collections::HashMap;

async fn search(params: HashMap<String, String>) -> impl IntoResponse {
    let query = params.get("q").unwrap_or(&"".to_string());
    let page = params.get("page").and_then(|p| p.parse::<u32>().ok()).unwrap_or(1);
    Text(format!("搜索: {},页码: {}", query, page))
}

Router::new().route("/search", get(search));

POST 表单

普通 POST 处理函数同样接收 HashMap<String, String>,数据来自 application/x-www-form-urlencoded 格式的请求体。

async fn login(params: HashMap<String, String>) -> impl IntoResponse {
    let username = params.get("username").cloned().unwrap_or_default();
    let password = params.get("password").cloned().unwrap_or_default();
    // 处理登录...
    Text("登录成功".to_string())
}

POST JSON

使用 post_json 可以自动将 JSON 请求体反序列化为指定的类型(需实现 Deserialize)。

use serde::Deserialize;

#[derive(Deserialize)]
struct CreateUser {
    name: String,
    email: String,
}

async fn create_user(data: CreateUser) -> impl IntoResponse {
    // 使用 data.name 和 data.email
    Json(format!("创建用户: {}", data.name))
}

Router::new().route("/users", post_json(create_user));

错误处理

通过返回 Result<T, E> 可以方便地处理错误,其中 TE 都必须实现 IntoResponse

use nimble::{Text, StatusCode};

async fn get_user() -> Result<Text, StatusCode> {
    // 模拟用户查找
    let user = find_user().await.ok_or(StatusCode::NOT_FOUND)?;
    Ok(Text(format!("用户名: {}", user)))
}

Router::new().route("/profile", get(|_| get_user()));

许可证

本项目采用以下许可证之一:

你可以自由选择使用其中任意一种。