axum_responses 0.4.6

A Simple way to use Axum responses
Documentation
use axum::{http::StatusCode, response::IntoResponse};

use crate::http::HttpResponse;

pub type FileResult = Result<FileResponse, HttpResponse>;

#[derive(Default, Debug)]
pub struct FileResponse {
    bytes: Option<Vec<u8>>,
    filename: String,
    content_type: String,
    disposition: ContentDisposition,
}

#[derive(Debug, Default)]
pub enum ContentDisposition {
    Inline,
    #[default]
    Attachment,
}

impl FileResponse {
    pub fn builder() -> FileResponse {
        FileResponse::default()
    }

    pub fn bytes(mut self, bytes: Vec<u8>) -> Self {
        self.bytes = Some(bytes);
        self
    }

    pub fn filename(mut self, filename: &str) -> Self {
        self.filename = filename.to_string();
        self
    }

    pub fn disposition(mut self, disposition: ContentDisposition) -> Self {
        self.disposition = disposition;
        self
    }

    pub fn content_type(mut self, content_type: &str) -> Self {
        self.content_type = content_type.to_string();
        self
    }

    #[doc(hidden)]
    pub fn build(self) -> impl IntoResponse {
        let bytes = self.bytes.unwrap_or_default();
        let disposition = match self.disposition {
            ContentDisposition::Inline => "inline",
            ContentDisposition::Attachment => "attachment",
        };

        let filename = if self.filename.is_empty() {
            "file"
        } else {
            &self.filename
        };

        (
            StatusCode::OK,
            [
                ("Content-type", self.content_type.as_str()),
                (
                    "Content-disposition",
                    &format!("{disposition}; filename=\"{filename}\""),
                ),
            ],
            bytes,
        )
            .into_response()
    }
}

impl IntoResponse for FileResponse {
    fn into_response(self) -> axum::response::Response {
        self.build().into_response()
    }
}