spring-axum 0.1.3

Spring-like application framework for Axum with macro-based auto discovery, validation, transactions, caching, events, and SQL/Mapper integrations.
Documentation
#![cfg(all(feature = "validator", feature = "axum_extra_json"))]

use axum::{Router, routing::post, http::{Request, StatusCode}};
use axum::body::{Body, to_bytes};
use serde::Deserialize;
use validator::Validate;
use tower::ServiceExt;

#[derive(Debug, Deserialize, Validate)]
struct StreamUser {
    #[validate(length(min = 2))]
    name: String,
}

async fn create_stream_user(spring_axum::ValidatedJsonStream(user): spring_axum::ValidatedJsonStream<StreamUser>) -> String {
    format!("ok:{}", user.name)
}

#[tokio::test]
async fn json_stream_validation_failure_and_success() {
    let app = Router::new().route("/users-stream", post(create_stream_user));

    // invalid: name too short
    let req_bad = Request::builder()
        .method("POST")
        .uri("/users-stream")
        .header("content-type", "application/json")
        .body(Body::from(r#"{"name":"a"}"#))
        .unwrap();
    let res_bad = app.clone().oneshot(req_bad).await.unwrap();
    assert_eq!(res_bad.status(), StatusCode::BAD_REQUEST);
    let body_bad = to_bytes(res_bad.into_body(), usize::MAX).await.unwrap();
    let v_bad: serde_json::Value = serde_json::from_slice(&body_bad).unwrap();
    assert!(v_bad.get("errors").is_some());
    assert!(v_bad.get("errors").unwrap().get("name").is_some());

    // valid: name length ok
    let req_ok = Request::builder()
        .method("POST")
        .uri("/users-stream")
        .header("content-type", "application/json")
        .body(Body::from(r#"{"name":"alice"}"#))
        .unwrap();
    let res_ok = app.clone().oneshot(req_ok).await.unwrap();
    assert_eq!(res_ok.status(), StatusCode::OK);
    let body_ok = to_bytes(res_ok.into_body(), usize::MAX).await.unwrap();
    assert_eq!(std::str::from_utf8(&body_ok).unwrap(), "ok:alice");
}