1use axum::http::{HeaderMap, HeaderValue, StatusCode};
4use axum::response::{IntoResponse, Response};
5use serde::Serialize;
6
7pub struct ViewResponse {
9 pub status: StatusCode,
10 pub body: String,
11 pub headers: HeaderMap,
12}
13
14impl ViewResponse {
15 pub fn new(body: impl Into<String>) -> Self {
16 let mut headers = HeaderMap::new();
17 headers.insert(
18 axum::http::header::CONTENT_TYPE,
19 HeaderValue::from_static("text/html; charset=utf-8"),
20 );
21 Self {
22 status: StatusCode::OK,
23 body: body.into(),
24 headers,
25 }
26 }
27
28 pub fn status(mut self, s: StatusCode) -> Self {
29 self.status = s;
30 self
31 }
32}
33
34impl IntoResponse for ViewResponse {
35 fn into_response(self) -> Response {
36 (self.status, self.headers, self.body).into_response()
37 }
38}
39
40pub struct Redirect {
42 pub status: StatusCode,
43 pub location: String,
44 pub flash: Option<(String, String)>,
45}
46
47impl Redirect {
48 pub fn to(location: impl Into<String>) -> Self {
49 Self {
50 status: StatusCode::SEE_OTHER,
51 location: location.into(),
52 flash: None,
53 }
54 }
55
56 pub fn back() -> Self {
57 Self::to("/")
58 }
59
60 pub fn permanent(location: impl Into<String>) -> Self {
61 Self {
62 status: StatusCode::MOVED_PERMANENTLY,
63 location: location.into(),
64 flash: None,
65 }
66 }
67
68 pub fn with(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
69 self.flash = Some((key.into(), value.into()));
70 self
71 }
72}
73
74impl IntoResponse for Redirect {
75 fn into_response(self) -> Response {
76 let mut headers = HeaderMap::new();
77 headers.insert(
78 axum::http::header::LOCATION,
79 HeaderValue::from_str(&self.location)
80 .unwrap_or_else(|_| HeaderValue::from_static("/")),
81 );
82 (self.status, headers).into_response()
83 }
84}
85
86pub trait Responder {
89 fn respond(self) -> Response;
90}
91
92impl<T: IntoResponse> Responder for T {
93 fn respond(self) -> Response {
94 self.into_response()
95 }
96}
97
98pub fn json<T: Serialize>(value: T) -> axum::Json<T> {
99 axum::Json(value)
100}
101
102pub fn no_content() -> Response {
103 (StatusCode::NO_CONTENT).into_response()
104}