unleash_api_client/
lib.rs

1// Copyright 2020,2021,2022 Cognite AS
2/*!
3[Unleash](https://unleash.github.io) is a feature flag API system. This is a
4client for it to facilitate using the API to control features in Rust programs.
5
6## Client overview
7The client is written using async. Any std compatible async runtime should be
8compatible. Examples with async-std and tokio are in the examples/ in the source
9tree.
10To use it in a sync program, run an async executor and `block_on()` the relevant
11calls. As the client specification requires sending background metrics to the API,
12you will need to arrange to call the `poll_for_updates` method from a thread as
13demonstrated in `examples/threads.rs`.
14The unleash defined strategies are included, to support custom strategies
15use the `ClientBuilder` and call the `strategy` method to register your custom
16strategy memoization function.
17```no_run
18# mod i {
19# cfg_if::cfg_if!{
20#   if #[cfg(not(feature = "surf-client"))] {
21#  pub fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
22#      Ok(())
23# }
24# } else {
25use std::collections::hash_map::HashMap;
26use std::collections::hash_set::HashSet;
27use std::hash::BuildHasher;
28use std::time::Duration;
29use async_std::task;
30use futures_timer::Delay;
31use serde::{Deserialize, Serialize};
32use enum_map::Enum;
33use unleash_api_client::client;
34use unleash_api_client::config::EnvironmentConfig;
35use unleash_api_client::context::Context;
36use unleash_api_client::strategy;
37fn _reversed_uids<S: BuildHasher>(
38    parameters: Option<HashMap<String, String, S>>,
39) -> strategy::Evaluate {
40    let mut uids: HashSet<String> = HashSet::new();
41    if let Some(parameters) = parameters {
42        if let Some(uids_list) = parameters.get("userIds") {
43            for uid in uids_list.split(',') {
44                uids.insert(uid.chars().rev().collect());
45            }
46        }
47    }
48    Box::new(move |context: &Context| -> bool {
49        context
50            .user_id
51            .as_ref()
52            .map(|uid| uids.contains(uid))
53            .unwrap_or(false)
54    })
55}
56#[allow(non_camel_case_types)]
57#[derive(Debug, Deserialize, Serialize, Enum, Clone)]
58enum UserFeatures {
59    default
60}
61# pub
62fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
63    let _ = simple_logger::init();
64    task::block_on(async {
65        let config = EnvironmentConfig::from_env()?;
66        let client = client::ClientBuilder::default()
67            .strategy("reversed", Box::new(&_reversed_uids))
68            .into_client::<UserFeatures, unleash_api_client::prelude::DefaultClient>(
69                &config.api_url,
70                &config.app_name,
71                &config.instance_id,
72               config.secret,
73            )?;
74        client.register().await?;
75        futures::future::join(client.poll_for_updates(), async {
76            // Ensure we have initial load of features completed
77            Delay::new(Duration::from_millis(500)).await;
78            assert_eq!(true, client.is_enabled(UserFeatures::default, None, false));
79            // ... serve more requests
80            client.stop_poll().await;
81        }).await;
82        Ok(())
83    })
84}
85#   }
86#  }
87# }
88# fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
89#     i::main()
90# }
91```
92 Previously there was a Re-export of enum_map::Enum - this trait is part of
93 our public API. But there is a bug:
94 https://gitlab.com/KonradBorowski/enum-map/-/issues/22 so instead you must
95 match the version in your dependencies.
96
97## Crate features
98
99* **backtrace** -
100  Enable backtrace feature in anyhow (nightly only)
101* **default** -
102  By default no features are enabled.
103* **functional** -
104  Only relevant to developers: enables the functional test suite.
105* **reqwest-client** -
106  Enables reqwest with OpenSSL TLS support
107* **reqwest-client-11** -
108  Enables reqwest 0.11 with OpenSSL TLS support
109* **reqwest-client-rustls** -
110  Enables reqwest with RusTLS support
111* **reqwest-client-11-rustls** -
112  Enables reqwest 0.11 with RusTLS support
113* **strict** -
114  Turn unexpected fields in API responses into errors
115*/
116#![warn(clippy::all)]
117
118pub mod api;
119pub mod client;
120pub mod config;
121pub mod context;
122pub mod http;
123pub mod strategy;
124pub mod version;
125
126// Exports for ergonomical use
127pub use crate::client::{Client, ClientBuilder};
128pub use crate::config::EnvironmentConfig;
129pub use crate::context::Context;
130pub use crate::strategy::Evaluate;
131
132/// For the complete minimalist
133///
134/// ```no_run
135/// use serde::{Deserialize, Serialize};
136/// use enum_map::Enum;
137/// use unleash_api_client::prelude::*;
138///
139/// let config = EnvironmentConfig::from_env()?;
140///
141/// #[allow(non_camel_case_types)]
142/// #[derive(Debug, Deserialize, Serialize, Enum, Clone)]
143/// enum UserFeatures {
144///     feature
145/// }
146///
147/// let client = ClientBuilder::default()
148///     .into_client::<UserFeatures, DefaultClient>(
149///         &config.api_url,
150///         &config.app_name,
151///         &config.instance_id,
152///         config.secret,
153///         )?;
154/// # Ok::<(), Box<dyn std::error::Error + std::marker::Send + std::marker::Sync>>(())
155/// ```
156pub mod prelude {
157    pub use crate::client::ClientBuilder;
158    pub use crate::config::EnvironmentConfig;
159    cfg_if::cfg_if! {
160        if #[cfg(feature = "reqwest")] {
161            pub use reqwest::Client as DefaultClient;
162        } else if #[cfg(feature = "reqwest-11")] {
163            pub use reqwest_11::Client as DefaultClient;
164        }
165    }
166}