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).unwrap_or_else(|_| HeaderValue::from_static("/")),
80 );
81 (self.status, headers).into_response()
82 }
83}
84
85pub trait Responder {
88 fn respond(self) -> Response;
89}
90
91impl<T: IntoResponse> Responder for T {
92 fn respond(self) -> Response {
93 self.into_response()
94 }
95}
96
97pub fn json<T: Serialize>(value: T) -> axum::Json<T> {
98 axum::Json(value)
99}
100
101pub fn no_content() -> Response {
102 (StatusCode::NO_CONTENT).into_response()
103}