nidrs 0.4.0

Nidrs is a web framework based on axum and tokio.
Documentation
use axum::Json;
use nidrs_extern::axum::{http::StatusCode, response::IntoResponse};
use nidrs_extern::{colored::Colorize, *};

#[cfg(feature = "valid")]
use nidrs_valid::validator::ValidError;

pub type AppResult<T = ()> = Result<T, AppError>;

#[derive(thiserror::Error, Debug)]
pub enum AppError {
    #[error("Environment variable not found")]
    EnvironmentVariableNotFound(#[from] std::env::VarError),

    #[error(transparent)]
    IOError(#[from] std::io::Error),

    #[error(transparent)]
    SerdeError(#[from] serde_json::Error),

    #[error(transparent)]
    TokioJoinError(#[from] tokio::task::JoinError),

    #[cfg(feature = "valid")]
    #[error(transparent)]
    ValidError(#[from] ValidError),

    #[error("Compilation Error")]
    CompilationError(String),

    #[error(transparent)]
    Exception(#[from] Exception),
}

impl IntoResponse for AppError {
    fn into_response(self) -> axum::response::Response {
        let t = format!("Error: {:?}", self);
        nidrs_macro::elog!("{}", t);
        if let AppError::Exception(e) = self {
            return e.into_response();
        }
        axum::response::Response::builder().status(StatusCode::INTERNAL_SERVER_ERROR).body(t).unwrap().into_response()
    }
}

pub fn __throw<E: Into<AppError>>(e: E, line: &str) -> AppResult<()> {
    let e = e.into();
    if let AppError::Exception(mut e) = e {
        e.line = line.to_string();
        print!("{}", "[nidrs] Exception ".red().bold());
        println!("{}", e.to_string().red().bold());
        return Err(e.into());
    }
    Err(e)
}

#[derive(thiserror::Error, Debug)]
pub struct Exception {
    pub status: StatusCode,
    pub error: anyhow::Error,
    pub line: String,
}

impl Exception {
    pub fn new(status: StatusCode, error: anyhow::Error) -> Self {
        Exception { status, error, line: String::new() }
    }
}

impl std::fmt::Display for Exception {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "HTTP Exception: status={}, error={}\n   {}", self.status, self.error, self.line)
    }
}

impl IntoResponse for Exception {
    fn into_response(self) -> axum::response::Response {
        axum::response::Response::builder().status(self.status).body(self.error.to_string()).unwrap().into_response()
    }
}

pub fn result_to_json<T: IntoResponse>(result: AppResult<T>) -> Json<axum::response::Response> {
    match result {
        Ok(t) => Json(t.into_response()),
        Err(e) => Json(e.into_response()),
    }
}