titan_core/respond.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
use std::convert::Infallible;
use titan_http::{body::Body, header, Response, ResponseBuilder, StatusCode};
/// A trait for types that can be converted into an HTTP response.
///
/// The `Respondable` trait is intended for types that can be transformed into a valid HTTP response.
/// Any type returned by a handler (or any function) that implements this trait can be converted into
/// a `Response<Body>`. This is typically used to ensure that different types can be unified into
/// a standard response format for HTTP APIs or services.
///
/// This method converts the implementing type into an HTTP response represented by a `Response<Body>`.
/// It allows various types (e.g., structs, enums, or other custom types) to be returned from a handler
/// and automatically converted into HTTP responses.
///
/// # Implementing `Respondable`
///
/// To implement the `Respondable` trait, you need to define how your custom type can be turned into
/// an HTTP response. This is commonly done by converting your type into a response body (e.g., a string,
/// JSON, or some binary data) and returning it wrapped in a `Response<Body>`.
///
/// # Example
///
/// ```
/// use titan_http::{body::Body, Response};
/// use titan_core::Respondable;
///
/// // Define a type that represents a response body.
/// pub struct MyResponse {
/// message: String,
/// }
///
/// // Implement `Respondable` for `MyResponse`.
/// impl Respondable for MyResponse {
/// fn respond(self) -> Response<Body> {
/// // Convert the struct into an HTTP response with the message in the body.
/// Response::new(Body::from(self.message))
/// }
/// }
///
/// // Now you can return `MyResponse` from a handler, and it will be automatically
/// // converted into an HTTP response.
/// ```
pub trait Respondable {
fn respond(self) -> Response<Body>;
}
impl<T, E> Respondable for Result<T, E>
where
T: Respondable,
E: Respondable,
{
fn respond(self) -> Response<Body> {
match self {
Ok(t) => t.respond(),
Err(e) => e.respond(),
}
}
}
impl Respondable for Response<Body> {
fn respond(self) -> Response<Body> {
self
}
}
impl Respondable for Infallible {
fn respond(self) -> Response<Body> {
panic!("Not fallible :(")
}
}
impl Respondable for () {
fn respond(self) -> Response<Body> {
ResponseBuilder::new().status(204).body(Body::from(())).unwrap()
}
}
impl<T> Respondable for (StatusCode, T)
where
T: Respondable,
{
fn respond(self) -> Response<Body> {
let (status, body) = self;
let mut res = body.respond();
*res.status_mut() = status;
res
}
}
impl Respondable for titan_html::tags::html::Html {
fn respond(self) -> Response<Body> {
let str = titan_html::render(self);
let response = ResponseBuilder::new().status(200);
response
.header(header::CONTENT_TYPE, "text/html")
.body(Body::from(str))
.unwrap()
}
}
macro_rules! impl_respondable_for_int {
($($t:ty)*) => {
$(
impl Respondable for $t {
fn respond(self) -> Response<Body> {
let body = Body::from(self);
let mut res = Response::new(body);
let headers = res.headers_mut();
headers.insert("content-type", "text/plain".parse().unwrap());
res
}
}
)*
};
}
impl_respondable_for_int!(String &str i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 usize isize);