lib-humus 0.6.0

Helps creating configurable frontends for humans and computers using axum, Tera and toml.
Documentation
// SPDX-FileCopyrightText: 2026 Slatian <baschdel@disroot.org>
//
// SPDX-License-Identifier: AGPL-3.0-or-later

use axum::http::status::StatusCode;
use axum::response::IntoResponse;
use axum::response::Json;
use axum::response::Response;
use serde::Serialize;
use tera::Context;

use crate::HumusQuerySettings;
use crate::templating::HumusApiFormat;

/// πŸ‘ Provides data and logic for the [HumusEngine] and
/// knows how to put information together.
///
/// It is recommended to implement this as an enum carrying additional information.
///
/// πŸ’‘Also have a look at the provided methods, while they may be sane defaults
/// they are probably not always the desired behavior.
///
/// [HumusEngine]: ./struct.HumusEngine.html
pub trait HumusView<S, ApiFormat>: Serialize + Sized
where
	S: HumusQuerySettings,
	ApiFormat: HumusApiFormat,
{
	/// Returns the template name that will be used to select
	/// the template file.
	///
	/// If the name is "404" for an html response the template
	/// file "404.html" will be used.
	///
	/// Also ends up as the `view` variable in the template.
	/// Example:
	/// ```rust,ignore
	/// fn get_template_name(&self) -> String {
	/// 	match self {
	/// 		Self::Index{..} => "index",
	/// 		Self::Results{..} => "results",
	/// 		Self::NotFound => "404",
	/// 		Self::InternalError{..} => "500",
	/// 	}.to_string()
	/// }
	/// ```
	fn get_template_name(&self) -> String;

	/// Returns the reponse code for the view.
	///
	/// The numeric value will be useable as `http_status` in the template.
	///
	/// Example:
	/// ```rust,ignore
	/// use axum::http::StatusCode;
	///
	/// fn get_status_code(&self, settings: &SomeSettings) -> StatusCode {
	/// 	match self {
	/// 		Self::NotFound => StatusCode::NOT_FOUND,
	/// 		Self::InternalError{..} => StatusCode::INTERNAL_SERVER_ERROR,
	/// 		_ => StatusCode::OK,
	/// 	}
	/// }
	/// ```
	fn get_status_code(&self, settings: &S) -> StatusCode;

	/// [Hook called before rendering a template][crate::templating::TemplatingEngine::render_view]
	/// to initalize it with additional values.
	///
	/// πŸ“– Remember to document which values you set here in a place someone who
	/// wants to do something with templating is able to find it.
	///
	/// The default implementation does nothing.
	fn initalize_template_context(&self, _context: &mut Context, _settings: &S) {}

	/// [Hook to update non-API responses][crate::templating::TemplatingEngine::render_view]
	/// after they have been built.
	///
	/// **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.
	///
	/// When migrating from earlier versions set your cookie headers in here.
	/// See also [axum: Constructing a Cookie][axum_extra::extract::cookie::Cookie#constructing-a-cookie]
	///
	/// Useful for setting extra headers. Does nothing by default.
	fn update_response(&self, response: Response, _settings: &S) -> Response {
		response
	}

	/// Return an API-Response
	///
	/// By default causes the view to Serialize itself
	/// to a json response using serde.
	///
	/// Response code and cookie headers are queried in
	/// advance and set on the reulting response if it has a status code of 200.
	/// Otherwise it is assumed that the response generating logic
	/// alredy took care of that.
	///
	/// You'll need the following imports when implementing:
	/// ```
	/// use axum::Json;
	/// use axum::response::IntoResponse;
	/// ```
	///
	/// The api format in the seconds argument is guaranteed to be derived from the settings given in the first argument.
	fn into_api_response(self, settings: &S, _api_format: ApiFormat) -> Response {
		let response = Json(&self).into_response();
		self.update_response(response, settings)
	}
}