restrepo 0.5.12

A collection of components for building restful webservices with actix-web
Documentation
//! Provides uniform return types, functionality to handle application configuration and facilitate error handling

use clap::Parser;
use serde::de::DeserializeOwned;
use std::fmt::Debug;

/// Collects commandline parameters and can be used to parse config files or environment variables.
/// Commandline parameters are:
///  
/// `address (Defaults to [::]:8000)`: the server address
///
/// `debug (Defaults to false)`: whether to start the application in debug mode
///
/// `env_prefix (Optional)`: enables collecting further application config items from environment variables beginning with the specified prefix
///
/// `config_path (Optional)`: enables collecting further application config items from a file at the specified path
/// ### Example
/// ```no_run
/// use clap::Parser;
/// use restrepo::server::ApplicationParameters;
/// use serde::Deserialize;
///
/// #[derive(Deserialize)]
/// struct Settings {
///     database_url: String,
///     file_storage_path: String
/// }
///
/// let app_params = ApplicationParameters::try_parse().unwrap();
/// let app_settings: Settings = app_params.load_app_config().unwrap();
/// ```
#[derive(Parser)]
#[command(name = env!("CARGO_PKG_NAME"))]
#[command(about = "A webserver built with restrepo", long_about = None)]
pub struct ApplicationParameters {
    #[clap(
        default_value_t = String::from("[::]:8000"),
        short,
        help = "Specify address for server to listen on."
    )]
    pub address: String,
    #[clap(
        short,
        help = "Sets log level to debug. WARNING: Might leak sensitive information."
    )]
    pub debug: bool,
    #[clap(
        short,
        help = "Collect settings from environment variables prefixed by <ENV_PREFIX>."
    )]
    pub env_prefix: Option<String>,
    #[clap(
        short,
        help = "Collect settings from application configuration file at this path."
    )]
    pub config_path: Option<String>,
}

impl ApplicationParameters {
    /// Attempts to load configuration parameters from environment variables or a file location if any are provided
    /// through [ApplicationParameters].
    pub fn load_app_config<T: DeserializeOwned>(&self) -> anyhow::Result<T> {
        let mut cfgbuilder = config::Config::builder();
        if let Some(path) = &self.config_path
            && std::fs::metadata(path).is_ok()
        {
            cfgbuilder = cfgbuilder.add_source(config::File::with_name(path));
        }
        if let Some(prefix) = &self.env_prefix {
            cfgbuilder = cfgbuilder
                .add_source(config::Environment::with_prefix(prefix).prefix_separator("_"));
        }
        let cfg = cfgbuilder.build()?;
        Ok(cfg.try_deserialize::<T>()?)
    }
}

/// Can be used to map and cast most errors into [std::io::Error], which is an expected return type by the [actix_web::main] macro
pub fn handle_application_startup_error<T: ToString + Debug + Send + Sync + 'static>(
    e: T,
) -> std::io::Error {
    std::io::Error::other(e.to_string())
}