From fbcd1715e99ed3b6e76fcc213fb379ffe2d378d7 Mon Sep 17 00:00:00 2001 From: Yago Iglesias Date: Sat, 2 Sep 2023 00:02:28 +0200 Subject: [PATCH] feat(config): Allow the use of environment variables in the configuration file I also added a way of deserilizing numbers --- Cargo.lock | 12 ++++++++++ Cargo.toml | 1 + spec.yml | 51 +++++++++++++++++++++++++++++++++++++++++++ src/configurations.rs | 14 +++++++++--- 4 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 spec.yml diff --git a/Cargo.lock b/Cargo.lock index c8fc1b4..a45df25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1658,6 +1658,17 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-aux" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3dfe1b7eb6f9dcf011bd6fad169cdeaae75eda0d61b1a99a3f015b41b0cae39" +dependencies = [ + "chrono", + "serde", + "serde_json", +] + [[package]] name = "serde_derive" version = "1.0.188" @@ -2517,6 +2528,7 @@ dependencies = [ "reqwest", "secrecy", "serde", + "serde-aux", "sqlx", "tokio", "tracing", diff --git a/Cargo.toml b/Cargo.toml index 6157017..b2f25e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ tracing-log = "0.1" once_cell = "1" secrecy = { version = "0.8", features = ["serde"] } tracing-actix-web = "0.7" +serde-aux = "4" [dev-dependencies] reqwest = { version = "0.11", features = ["json"] } diff --git a/spec.yml b/spec.yml new file mode 100644 index 0000000..47704db --- /dev/null +++ b/spec.yml @@ -0,0 +1,51 @@ +name: zero2prod +# Check https://www.digitalocean.com/docs/app-platform/#regional-availability +# for a list of all the available options. +# You can get region slugs from +# https://www.digitalocean.com/docs/platform/availability-matrix/ +# They must specified lowercased. +# `fra` stands for Frankfurt (Germany - EU) +region: fra +services: + - name: zero2prod + # Relative to the repository root + dockerfile_path: Dockerfile + source_dir: . + github: + # Depending on when you created the repository, + # the default branch on GitHub might have been named `master` + branch: master + # Deploy a new version on every commit to `main`! + # Continuous Deployment, here we come! + deploy_on_push: true + # !!! Fill in with your details + # e.g. LukeMathWalker/zero-to-production + repo: Yag000/zero2prod + # Active probe used by DigitalOcean's to ensure our application is healthy + health_check: + # The path to our health check endpoint! + # It turned out to be useful in the end! + http_path: /health_check + # The port the application will be listening on for incoming requests + # It should match what we specified in our configuration/production.yaml file! + http_port: 8000 + # For production workloads we'd go for at least two! + # But let's try to keep the bill under control for now... + instance_count: 1 + instance_size_slug: basic-xxs + # All incoming requests should be routed to our app + routes: + - path: / + +databases: + # PG = Postgres + - engine: PG + # Database name + name: + newsletter + # Again, let's keep the bill lean + num_nodes: 1 + size: + db-s-dev-database + # Postgres version - using the latest here + version: "12" diff --git a/src/configurations.rs b/src/configurations.rs index 2a150e6..ada0459 100644 --- a/src/configurations.rs +++ b/src/configurations.rs @@ -1,6 +1,6 @@ use config::Config; use secrecy::{ExposeSecret, Secret}; - +use serde_aux::field_attributes::deserialize_number_from_string; #[derive(serde::Deserialize)] pub struct Settings { pub database: DatabaseSettings, @@ -9,15 +9,17 @@ pub struct Settings { #[derive(serde::Deserialize)] pub struct DatabaseSettings { + #[serde(deserialize_with = "deserialize_number_from_string")] + pub port: u16, pub username: String, pub password: Secret, - pub port: u16, pub host: String, pub database_name: String, } #[derive(serde::Deserialize)] pub struct ApplicationSettings { + #[serde(deserialize_with = "deserialize_number_from_string")] pub port: u16, pub host: String, } @@ -53,11 +55,17 @@ pub fn get_configuration() -> Result { .unwrap_or_else(|_| "local".into()) .try_into() .expect("Failed to parse APP_ENVIRONMENT."); + let environment_filename = format!("{}.yaml", environment.as_str()); let settings = Config::builder() .add_source(config::File::from(configuration_directory.join("base")).required(true)) .add_source( - config::File::from(configuration_directory.join(environment.as_str())).required(true), + config::File::from(configuration_directory.join(environment_filename)).required(true), + ) + .add_source( + config::Environment::with_prefix("APP") + .prefix_separator("_") + .separator("__"), ); match settings.build() {