sinan 0.1.0

A Boilerplate for Rapid Axum Web Service Deployment.
Documentation
use std::borrow::Cow;

use axum::body::Body;
use http::{header, StatusCode};
use serde::Serialize;
use serde_json::{json, Value};

use crate::http::response;
use crate::support::database::Paginator;
use crate::SharedString;

mod error;

#[derive(Debug, Serialize)]
pub struct Response {
    code: u16,
    success: bool,
    data: Value,
    message: Option<SharedString>,
}

impl Response {
    fn new(code: StatusCode) -> Self {
        Self {
            code: code.as_u16(),
            success: code.is_success(),
            data: Value::Object(Default::default()),
            message: code.canonical_reason().map(Cow::Borrowed), // TODO 根据 code 枚举取 message
        }
    }

    pub fn code(&mut self, code: StatusCode) -> &mut Self {
        self.code = code.as_u16();
        self.message = code.canonical_reason().map(Cow::Borrowed);
        self.success = code.is_success();

        self
    }

    pub fn data<T: Serialize>(&mut self, data: &T) -> &mut Self {
        match serde_json::to_value(data) {
            Ok(value) => self.data = value,
            Err(err) => self.message = Some(Cow::from(err.to_string())),
        }

        self
    }

    pub fn paginator(&mut self, paginator: Paginator) -> &mut Self {
        let data = json!({
            "items": paginator.items,
            "meta":{
                "pagination": {
                    "count": paginator.count,
                    "per_page": paginator.per_page,
                    "current_page": paginator.current_page,
                    "total": paginator.total,
                    "total_pages": paginator.total_pages,
                }
            }
        });

        self.data(&data)
    }

    pub fn message(&mut self, message: impl Into<SharedString>) -> &mut Self {
        let message = message.into();

        self.message = Some(message);

        self
    }

    pub fn json(&self) -> axum::response::Response {
        let bytes = serde_json::to_vec(&self).unwrap_or_else(|err| err.to_string().into_bytes());

        axum::response::Response::builder()
            .header(header::CONTENT_TYPE, "application/json; charset=utf-8")
            .body(Body::from(bytes))
            .unwrap_or_default()
    }
}

impl Default for Response {
    fn default() -> Self {
        Self::new(StatusCode::OK)
    }
}