axum-msgpack 0.4.0

serialize/derserialize msgpack for axum
Documentation
use crate::error::Error;
use axum::{
    body::Body,
    extract::rejection::BytesRejection,
    http,
    response::{IntoResponse, Response},
    BoxError,
};

#[derive(Debug)]
#[non_exhaustive]
pub struct InvalidMsgPackBody(Error);

impl InvalidMsgPackBody {
    pub(crate) fn from_err<E>(err: E) -> Self
    where
        E: Into<BoxError>,
    {
        Self(Error::new(err))
    }
}

impl IntoResponse for InvalidMsgPackBody {
    fn into_response(self) -> Response {
        let mut res = Response::new(Body::from(format!(
            "Failed to parse the request body as MsgPack: {}",
            self.0
        )));
        *res.status_mut() = http::StatusCode::BAD_REQUEST;
        res
    }
}

impl std::fmt::Display for InvalidMsgPackBody {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "Failed to parse the request body as MsgPack")
    }
}

impl std::error::Error for InvalidMsgPackBody {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        Some(&self.0)
    }
}

#[derive(Debug)]
#[non_exhaustive]
/// Rejection type for [`MsgPack`](super::MsgPack) used if the `Content-Type`
/// header is missing
pub struct MissingMsgPackContentType;

impl IntoResponse for MissingMsgPackContentType {
    fn into_response(self) -> Response {
        let mut res = Response::new(Body::from(
            "Expected request with `Content-Type: application/msgpack`",
        ));
        *res.status_mut() = http::StatusCode::BAD_REQUEST;
        res
    }
}

impl std::error::Error for MissingMsgPackContentType {}
impl std::fmt::Display for MissingMsgPackContentType {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "Expected request with `Content-Type: application/msgpack`"
        )
    }
}

#[derive(Debug)]
#[non_exhaustive]
pub struct BodyAlreadyExtracted;

impl IntoResponse for BodyAlreadyExtracted {
    fn into_response(self) -> Response {
        let mut res = Response::new(Body::from(
            "Cannot have two request body extractors for a single handler",
        ));
        *res.status_mut() = http::StatusCode::INTERNAL_SERVER_ERROR;
        res
    }
}

impl std::fmt::Display for BodyAlreadyExtracted {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "Cannot have two request body extractors for a single handler"
        )
    }
}

impl std::error::Error for BodyAlreadyExtracted {}

#[derive(Debug)]
#[non_exhaustive]
pub enum MsgPackRejection {
    InvalidMsgPackBody(InvalidMsgPackBody),
    MissingMsgPackContentType(MissingMsgPackContentType),
    BodyAlreadyExtracted(BodyAlreadyExtracted),
    BytesRejection(BytesRejection),
}

impl IntoResponse for MsgPackRejection {
    fn into_response(self) -> Response {
        match self {
            Self::InvalidMsgPackBody(inner) => inner.into_response(),
            Self::MissingMsgPackContentType(inner) => inner.into_response(),
            Self::BodyAlreadyExtracted(inner) => inner.into_response(),
            Self::BytesRejection(inner) => inner.into_response(),
        }
    }
}

impl From<InvalidMsgPackBody> for MsgPackRejection {
    fn from(inner: InvalidMsgPackBody) -> Self {
        Self::InvalidMsgPackBody(inner)
    }
}

impl From<BytesRejection> for MsgPackRejection {
    fn from(inner: BytesRejection) -> Self {
        Self::BytesRejection(inner)
    }
}

impl From<MissingMsgPackContentType> for MsgPackRejection {
    fn from(inner: MissingMsgPackContentType) -> Self {
        Self::MissingMsgPackContentType(inner)
    }
}

impl From<BodyAlreadyExtracted> for MsgPackRejection {
    fn from(inner: BodyAlreadyExtracted) -> Self {
        Self::BodyAlreadyExtracted(inner)
    }
}

impl std::fmt::Display for MsgPackRejection {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::InvalidMsgPackBody(inner) => write!(f, "{}", inner),
            Self::MissingMsgPackContentType(inner) => write!(f, "{}", inner),
            Self::BodyAlreadyExtracted(inner) => write!(f, "{}", inner),
            Self::BytesRejection(inner) => write!(f, "{}", inner),
        }
    }
}

impl std::error::Error for MsgPackRejection {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            Self::InvalidMsgPackBody(inner) => Some(inner),
            Self::MissingMsgPackContentType(inner) => Some(inner),
            Self::BodyAlreadyExtracted(inner) => Some(inner),
            Self::BytesRejection(inner) => Some(inner),
        }
    }
}