Expand description
confik
confik
is a library for reading application configuration split across multiple sources.
Example
Assume that config.toml
contains:
host=google.com
username=root
and the environment contains:
PASSWORD=hunter2
then:
use confik::{Configuration, EnvSource, FileSource, TomlSource};
#[derive(Debug, PartialEq, Configuration)]
struct Config {
host: String,
username: String,
#[confik(secret)]
password: String,
}
let config = Config::builder()
.override_with(FileSource::new("config.toml"))
.override_with(EnvSource::new().allow_secrets())
.try_build()
.unwrap();
assert_eq!(
config,
Config {
host: "google.com".to_string(),
username: "root".to_string(),
password: "hunter2".to_string(),
}
);
Sources
A Source
is any type that can create ConfigurationBuilder
s.
This crate implements the following sources:
EnvSource
: Loads configuration from environment variables using theenvious
crate. Requires theenv
feature. (Enabled by default.)FileSource
: Loads configuration from a file, detectingjson
ortoml
files based on the file extension. Requires thejson
andtoml
feature respectively. (toml
is enabled by default.)TomlSource
: Loads configuration from a TOML string literal. Requires thetoml
feature. (Enabled by default.)JsonSource
: Loads configuration from a JSON string literal. Requires thejson
feature.
Secrets
Fields annotated with #[confik(secret)]
will only be read from secure sources.
This serves as a runtime check that no secrets have been stored in insecure places such as
world-readable files.
If a secret is found in an insecure source, an error will be returned. You can opt into loading secrets on a source-by-source basis.
Foreign Types
This crate provides implementations of Configuration
for a number of std
types and the
following third-party crates. Implementations for third-party crates are feature gated.
chrono
-chrono
0.4rust_decimal
-rust_decimal
1url
-url
1uuid
-uuid
1
Macro usage
The derive macro is called Configuration
and is used as normal:
#[derive(confik::Configuration)]
struct Config {
data: usize,
}
Forwarding Attributes To Deserialize
The serde attributes used for customizing a Deserialize
derive typically are achieved by
adding #[confik(forward_serde(...))
attributes.
For example:
#[derive(confik::Configuration)]
struct Config {
#[confik(forward_serde(rename = "other_data"))]
data: usize,
}
Defaults
Defaults are specified on a per-field basis.
- Defaults are used if the data cannot be fully read, even if it is partially read.
E.g., even if
data
in the below example has one value read in, both will be overwritten by the default.use confik::{Configuration, TomlSource}; #[derive(Configuration)] struct Data { a: usize, b: usize, } #[derive(Configuration)] struct Config { #[confik(default = Data { a: 1, b: 2 })] data: Data } let toml = r#" [data] a = 1234 "#; let config = Config::builder() .override_with(TomlSource::new(toml)) .try_build() .unwrap(); assert_eq!(config.data.a, 1); let toml = r#" [data] a = 1234 b = 4321 "#; let config = Config::builder() .override_with(TomlSource::new(toml)) .try_build() .unwrap(); assert_eq!(config.data.a, 1234);
- Defaults can be given by any rust expression, and have
Into::into
run over them. E.g.,const DEFAULT_VALUE: u8 = 4; #[derive(confik::Configuration)] struct Config { #[confik(default = DEFAULT_VALUE)] a: u32, #[confik(default = "hello world")] b: String, #[confik(default = 5f32)] c: f32, }
- Alternatively, a default without a given value called
Default::default
. E.g.,use confik::{Configuration}; #[derive(Configuration)] struct Config { #[confik(default)] a: usize } let config = Config::builder().try_build().unwrap(); assert_eq!(config.a, 0);
Handling Foreign Types
If there’s a foreign type used in your config, then you will not be able to implement
Configuration
for it. Instead any type that implements Into
can be used.
struct ForeignType {
data: usize,
}
#[derive(confik::Configuration)]
struct MyForeignTypeCopy {
data: usize
}
impl From<MyForeignTypeCopy> for ForeignType {
fn from(copy: MyForeignTypeCopy) -> Self {
Self {
data: copy.data,
}
}
}
#[derive(confik::Configuration)]
struct Config {
#[confik(from = MyForeignTypeCopy)]
foreign_data: ForeignType
}
Macro Limitations
Option
Defaulting
Option
s cannot default to anything other than None
. I.e., the below example ignores the provided default.
const DEFAULT_DATA: Option<usize> = Some(5);
#[derive(Configuration)]
struct Config {
#[confik(default = DEFAULT_DATA)]
data: Option<usize>
}
let config = Config::builder().try_build().unwrap();
assert_eq!(config.data, None);
This behaviour occurs due to Option
s needing to have a default value of None
, as Option
al
configuration shouldn’t be required. This defaulting occurs inside the ConfigurationBuilder
implementation of Option
and so happens before the macro can try to default the value.
This is in principle fixable by special casing any value with an Option<...>
type, but this
has not been implemented due to the fragility that trying to exact match on the string value of
a type in a macro would bring. E.g., a custom type such as type MyOption = Option<usize>
would
then behave differently to using Option<usize>
directly.
Custom Deserialize
Implementations
If you’re using a custom Deserialize
implementation, then you cannot use the Configuration
derive macro. Instead, define the necessary config implementation manually like so:
#[derive(Debug, serde_with::DeserializeFromStr)]
enum MyEnum {
Foo,
Bar,
};
impl std::str::FromStr for MyEnum {
// ...
}
impl confik::Configuration for MyEnum {
type Builder = Option<Self>;
}
Note that the Option<Self>
builder type only works for simple types. For more info, see the
docs on Configuration
and ConfigurationBuilder
.
Modules
- common
common
Useful configuration types that services will likely otherwise re-implement
Structs
- Used to accumulate ordered sources from which its
Target
is to be built. - EnvSource
env
ASource
referring to environment variables. - A
Source
referring to a file path. - JsonSource
json
ASource
containing raw JSON data. - Captures the path of a missing value.
- Wrapper type for carrying secrets, auto-applied to builders when using the
#[config(secret)]
attribute. - TomlSource
toml
ASource
containing raw TOML data. - Captures the path of a secret found in a non-secret source.
Enums
- Possible error values.
Traits
- The target to be deserialized from multiple sources.
- A builder for a multi-source config deserialization.
- A source of configuration data.