ruest-framework 0.1.0

RUEST (Rust + NestJS) — framework backend : DI, modules, HTTP Axum, JWT, validation
Documentation
use std::sync::Arc;

use axum::body::Body;
use axum::http::{Request, StatusCode};
use axum::routing::get;
use axum::Router;
use ruest::security::{
    apply_jwt_layer, AuthUser, JwtService, SecurityConfig,
};
use tower::ServiceExt;

#[test]
fn sign_and_verify_roundtrip() {
    let config = SecurityConfig::dev();
    let jwt = JwtService::new(&config).expect("jwt");

    let token = jwt
        .sign_subject("user-1", vec!["user".into()])
        .expect("sign");

    let claims = jwt.verify(&token).expect("verify");
    assert_eq!(claims.sub, "user-1");
    assert!(claims.has_role("user"));
}

#[tokio::test]
async fn middleware_blocks_without_token() {
    let config = SecurityConfig::dev();
    let jwt = Arc::new(JwtService::new(&config).expect("jwt"));

    let app = apply_jwt_layer(
        Router::new().route("/private", get(|| async { "secret" })),
        jwt,
        &config,
    );

    let response = app
        .oneshot(
            Request::builder()
                .uri("/private")
                .body(Body::empty())
                .unwrap(),
        )
        .await
        .unwrap();

    assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
}

#[tokio::test]
async fn middleware_allows_public_and_bearer() {
    let config = SecurityConfig::dev();
    let jwt = Arc::new(JwtService::new(&config).expect("jwt"));
    let token = jwt.sign_subject("u1", vec![]).expect("token");

    async fn me(user: AuthUser) -> String {
        user.subject().to_string()
    }

    let app = apply_jwt_layer(
        Router::new()
            .route("/health", get(|| async { "ok" }))
            .route("/me", get(me)),
        jwt,
        &config,
    );

    let health = app
        .clone()
        .oneshot(
            Request::builder()
                .uri("/health")
                .body(Body::empty())
                .unwrap(),
        )
        .await
        .unwrap();
    assert_eq!(health.status(), StatusCode::OK);

    let me = app
        .oneshot(
            Request::builder()
                .uri("/me")
                .header("Authorization", format!("Bearer {token}"))
                .body(Body::empty())
                .unwrap(),
        )
        .await
        .unwrap();
    assert_eq!(me.status(), StatusCode::OK);
}