Skip to main content

lib_humus/
view.rs

1// SPDX-FileCopyrightText: 2026 Slatian <baschdel@disroot.org>
2//
3// SPDX-License-Identifier: AGPL-3.0-or-later
4
5use axum::http::status::StatusCode;
6use axum::response::IntoResponse;
7use axum::response::Json;
8use axum::response::Response;
9use serde::Serialize;
10use tera::Context;
11
12use crate::HumusQuerySettings;
13use crate::templating::HumusApiFormat;
14
15/// πŸ‘ Provides data and logic for the [HumusEngine] and
16/// knows how to put information together.
17///
18/// It is recommended to implement this as an enum carrying additional information.
19///
20/// πŸ’‘Also have a look at the provided methods, while they may be sane defaults
21/// they are probably not always the desired behavior.
22///
23/// [HumusEngine]: ./struct.HumusEngine.html
24pub trait HumusView<S, ApiFormat>: Serialize + Sized
25where
26	S: HumusQuerySettings,
27	ApiFormat: HumusApiFormat,
28{
29	/// Returns the template name that will be used to select
30	/// the template file.
31	///
32	/// If the name is "404" for an html response the template
33	/// file "404.html" will be used.
34	///
35	/// Also ends up as the `view` variable in the template.
36	/// Example:
37	/// ```rust,ignore
38	/// fn get_template_name(&self) -> String {
39	/// 	match self {
40	/// 		Self::Index{..} => "index",
41	/// 		Self::Results{..} => "results",
42	/// 		Self::NotFound => "404",
43	/// 		Self::InternalError{..} => "500",
44	/// 	}.to_string()
45	/// }
46	/// ```
47	fn get_template_name(&self) -> String;
48
49	/// Returns the reponse code for the view.
50	///
51	/// The numeric value will be useable as `http_status` in the template.
52	///
53	/// Example:
54	/// ```rust,ignore
55	/// use axum::http::StatusCode;
56	///
57	/// fn get_status_code(&self, settings: &SomeSettings) -> StatusCode {
58	/// 	match self {
59	/// 		Self::NotFound => StatusCode::NOT_FOUND,
60	/// 		Self::InternalError{..} => StatusCode::INTERNAL_SERVER_ERROR,
61	/// 		_ => StatusCode::OK,
62	/// 	}
63	/// }
64	/// ```
65	fn get_status_code(&self, settings: &S) -> StatusCode;
66
67	/// [Hook called before rendering a template][crate::templating::TemplatingEngine::render_view]
68	/// to initalize it with additional values.
69	///
70	/// πŸ“– Remember to document which values you set here in a place someone who
71	/// wants to do something with templating is able to find it.
72	///
73	/// The default implementation does nothing.
74	fn initalize_template_context(&self, _context: &mut Context, _settings: &S) {}
75
76	/// [Hook to update non-API responses][crate::templating::TemplatingEngine::render_view]
77	/// after they have been built.
78	///
79	/// **Note:** The default implementation of [Self::into_api_response] does call this method, when implementing a custom version of it it is your decision wheter to call it or not.
80	///
81	/// When migrating from earlier versions set your cookie headers in here.
82	/// See also [axum: Constructing a Cookie][axum_extra::extract::cookie::Cookie#constructing-a-cookie]
83	///
84	/// Useful for setting extra headers. Does nothing by default.
85	fn update_response(&self, response: Response, _settings: &S) -> Response {
86		response
87	}
88
89	/// Return an API-Response
90	///
91	/// By default causes the view to Serialize itself
92	/// to a json response using serde.
93	///
94	/// Response code and cookie headers are queried in
95	/// advance and set on the reulting response if it has a status code of 200.
96	/// Otherwise it is assumed that the response generating logic
97	/// alredy took care of that.
98	///
99	/// You'll need the following imports when implementing:
100	/// ```
101	/// use axum::Json;
102	/// use axum::response::IntoResponse;
103	/// ```
104	///
105	/// The api format in the seconds argument is guaranteed to be derived from the settings given in the first argument.
106	fn into_api_response(self, settings: &S, _api_format: ApiFormat) -> Response {
107		let response = Json(&self).into_response();
108		self.update_response(response, settings)
109	}
110}