#web-framework #axum #web #http #framework

nidrs

Nidrs 是基于 axum 和 tokio 的 Web 框架

10 个版本

0.0.11 2024年6月12日
0.0.10 2024年6月11日
0.0.8 2024年5月5日
0.0.7 2024年4月28日
0.0.1 2024年3月30日

#208HTTP服务器

Download history 160/week @ 2024-04-27 153/week @ 2024-05-04 3/week @ 2024-05-11 13/week @ 2024-05-18 2/week @ 2024-05-25 148/week @ 2024-06-01 275/week @ 2024-06-08 42/week @ 2024-06-15 4/week @ 2024-06-22 11/week @ 2024-06-29 47/week @ 2024-07-06

883 每月下载量
用于 nidrs-diesel

MIT 许可证

66KB
1K SLoC

Nidrs

借鉴 NestJS 框架,Nidrs 是一个基于 Rust 的企业级模块化开发框架,在 Axum 上开发和设计,同时受到了 NestJS 思想的启发。

Nidrs 提供了一种即插即用的应用程序架构,使开发者和团队能够轻松地创建高度可测试、可扩展、松耦合且易于维护的应用程序。

NestJS 是一个用于构建高效、可扩展的 Node.js 服务器端应用程序的框架。它使用渐进式 JavaScript,由 TypeScript 构建,并完全支持 TypeScript(但仍允许开发者使用纯 JavaScript 编写代码),并结合了 OOP(面向对象编程)、FP(函数式编程)和 FRP(函数式响应式编程)的元素。

重点

  • 模块封装 v0.0.1
    • 静态模块注册 v0.0.1
    • 可配置模块注册 v0.0.2
  • 依赖自动注入
    • 服务自动注入 v0.0.1
    • 动态服务注入 v0.0.3
    • 服务作用域(全局)v0.0.1
    • 服务作用域(模块)v0.0.6
    • 服务实例作用域(单例)v0.0.1
    • 服务实例作用域(请求级别)
    • 服务实例作用域(注入级别)
  • 分层架构
    • 控制器层 v0.0.1
      • 支持读取路由方法的元数据 v0.0.6
    • 服务层 v0.0.1
    • 模型层
  • 模块生命周期钩子
    • on_module_init v0.0.2
    • on_module_destroy v0.0.5
    • on_application_bootstrap(待定)
    • on_application_shutdown(待定)
  • 请求响应拦截器
    • 控制器作用域 v0.0.4
    • 全局作用域 v0.0.6
  • 请求参数验证
  • 基于请求参数验证的模拟服务
  • 统一返回类型 v0.0.4
  • 错误封装和处理 v0.0.4
  • 统一添加路由前缀 v0.0.5
    • app.default_prefix
    • #[meta(disable_default_prefix)]
  • 接口版本控制 v0.0.5
    • app.default_version
    • #[version("v1")]
  • 与 tower 中间件兼容
  • 自动 OpenAPI 文档
  • API 调用接口生成
  • 模块测试
  • 支持在 wasm 环境中运行
  • CLI 命令
  • 完整的文档和示例

示例

example/src/app/controller.rs

use std::{collections::HashMap, sync::Arc};

use axum::{extract::{Query, State}, http::{version, StatusCode}, Json};
use nidrs::{throw, version, Exception, Inject, StateCtx};
use nidrs_macro::{controller, get, meta, post, uses};

use crate::{shared::fn_test::fn_test, AppError, AppResult};

use super::{dto::{Status}, service::AppService};

// #[uses(LogInterceptor)]
#[version("v1")]
#[meta(role = "admin", auth = "true")]
#[meta(test = true)]
#[controller("/app")]
#[derive(Debug, Default)]
pub struct AppController {
    app_service: Inject<AppService>,
}

impl AppController {
    #[meta(arr = ["user"])]
    // #[uses(LogInterceptor)]
    #[version("v2")]
    #[get("/hello")]
    pub async fn get_hello_world(&self, Query(q): Query<HashMap<String, String>>) -> AppResult<Status> {
        println!("Query {:?}", q);
        // fn_test()?;
        Ok(Status { db: "ok".to_string(), redis: "ok".to_string() })
    }

    // #[uses(LogInterceptor)]
    #[get("/hello2")]
    pub async fn get_hello_world2(&self, Query(q): Query<HashMap<String, String>>) -> AppResult<String> {
        println!("Query {:?}", q);
        Ok(self.app_service.get_hello_world())
    }
    
    #[uses(LogInterceptor)]
    #[post("/hello")]
    pub async fn post_hello_world(&self, Query(q): Query<HashMap<String, String>>, Json(j): Json<serde_json::Value>) -> AppResult<String> {
        println!("Query {:?}", q);
        println!("Json {:?}", j);

        Ok("Hello, World2!".to_string())
    }
}

example/src/app/service.rs

use nidrs::Inject;
use nidrs_macro::{injectable, on_module_init};
use crate::user::service::UserService;

#[injectable()]
#[derive(Clone, Debug, Default)]
pub struct AppService{
    user_service: Inject<UserService>
}

impl AppService {
    pub fn get_hello_world(&self) -> String {
        self.user_service.extract().get_hello_world()
    }

    pub fn get_hello_world2(&self) -> String {
        "Hello, nidrs2xx333!".to_string()
    }
}

example/src/app/mod.rs

use nidrs::default_uses;
use nidrs_macro::module;

pub mod controller;
pub mod dto;
pub mod exception;
pub mod service;

use crate::modules::conf::ConfModule;
use crate::modules::conf::ConfOptions;
use crate::modules::log::LogModule;
use crate::modules::user::UserModule;
use controller::AppController;
use service::AppService;

#[default_uses(LogInterceptor)]
#[module({
    imports: [
        ConfModule::for_root(ConfOptions{
            log_level: "info".to_string(),
        }),
        LogModule,
        UserModule,
    ],
    controllers: [AppController],
    services: [AppService],
    exports: [AppService],
})]
#[derive(Clone, Debug, Default)]
pub struct AppModule;

example/src/main.rs

mod app;
mod conf;
mod user;
mod log;
mod shared;

pub use nidrs::AppResult;
pub use nidrs::AppError;

#[nidrs::main]
fn main() {
    let app = nidrs::NidrsFactory::create(app::AppModule);

    let app = app.default_prefix("/api/{version}");
    let app = app.default_version("v1");

    app.listen(3000).block();
}

运行示例

git clone https://github.com/nidrs/nidrs.git
cd nidrs/example
cargo run

启动日志

[nidrs] Registering module AppModule.
[nidrs] Registering interceptor LogInterceptor.
[nidrs] Registering controller AppController.
[nidrs] Registering router 'GET /api/v1/app/hello2'.
[nidrs] Registering router 'POST /api/v1/app/hello'.
[nidrs] Registering router 'GET /api/v2/app/hello'.
[nidrs] Registering service AppService.
[nidrs] Registering dyn service ConfOptions.
[nidrs] Registering module ConfModule.
[nidrs] Registering service ConfService.
[nidrs] Injecting ConfService.
[nidrs] Triggering event on_module_init for ConfService.
ConfService initialized with log_level: ConfOptions { log_level: "info" }
[nidrs] Registering module LogModule.
[nidrs] Registering service LogService.
[nidrs] Injecting LogService.
[nidrs] Registering module UserModule.
[nidrs] Registering controller UserController.
[nidrs] Registering router 'GET /api/v1/user/hello'.
[nidrs] Registering service UserService.
[nidrs] Injecting UserService.
[nidrs] Injecting UserController.
[nidrs] Injecting AppService.
[nidrs] Injecting AppController.
[nidrs] Injecting LogInterceptor.
[nidrs] Listening on 0.0.0.0:3000

赞助商

开源不容易,赞助也不容易。两者都需要勇气。我相信,那些给予爱的人将会得到爱的回报。愿你的好运从这次贡献开始~

访问赞助商在 [AfDian]

关于

整个框架目前处于早期阶段,0.x.x版本的框架正在测试中。稳定版本从1.0开始。然而,如果你只是需要一个类似于Axum的高级框架,而不需要后面提到的附加功能,你仍然可以尝试一下。

最后,如果有任何有兴趣的个人想要贡献和开发,他们欢迎加入下面的Discord服务器,为Rust社区做出贡献。

Discord服务器链接

依赖项

~13–24MB
~338K SLoC