async_mpesa/
config.rs

1use reqwest::header::{ HeaderMap, AUTHORIZATION };
2
3///Default v1 API base url
4pub const MPESA_SANDBOX_API_URL: &str = "https://sandbox.safaricom.co.ke";
5pub const MPESA_PRODUCTION_API_URL: &str = "https://api.safaricom.co.ke";
6
7pub trait Config: Clone {
8    fn headers(&self) -> HeaderMap;
9    fn url(&self, path: &str) -> String;
10    fn api_url(&self) -> &str;
11    fn access_token(&self) -> &str;
12}
13
14#[derive(Clone, Debug)]
15pub enum Environment {
16    Sandbox,
17    Production,
18}
19
20///Configuration for Mpesa API
21#[derive(Clone, Debug)]
22pub struct MpesaConfig {
23    api_url: String,
24    access_token: String,
25    environment: Environment,
26}
27
28/// Default configuration if none are overriden by the structs' method
29impl Default for MpesaConfig {
30    fn default() -> Self {
31        Self { 
32            api_url: MPESA_SANDBOX_API_URL.to_string(), 
33            access_token: std::env::var("MPESA_ACCESS_TOKEN").unwrap_or_else(|_| "".to_string()),
34            environment: Environment::Sandbox
35        }
36    }
37}
38
39impl MpesaConfig {
40    /// Creates a client with default [MPESA_API_URL] and default API key from the MPESA_ACCESS_TOKEN env var
41    pub fn new() -> Self {
42        Default::default()
43    }
44
45    /// To use a different API key different from the default MPESA_ACCESS_TOKEN env var
46    pub fn with_access_token<S: Into<String>>(mut self, access_token: S) -> Self {
47        self.access_token = access_token.into();
48        self
49    }
50
51    /// To use an API_URL different from the default [MPESA_API_URL]
52    pub fn with_api_url<S: Into<String>>(mut self, api_url: S) -> Self {
53        self.api_url = api_url.into();
54        self
55    }
56
57    pub fn with_environment(mut self, environment: Environment) -> Self {
58        self.environment = environment;
59        self
60    }
61}
62
63impl Config for MpesaConfig {
64    fn headers(&self) -> HeaderMap {
65        let mut headers = HeaderMap::new();
66        
67        headers.insert(
68            AUTHORIZATION, 
69            format!("Bearer {}", self.access_token).as_str().parse().unwrap(),
70        );
71
72        headers
73    }
74
75    fn url(&self, path: &str) -> String {
76        match &self.environment {
77            Environment::Sandbox => format!("{}{}", MPESA_SANDBOX_API_URL, path),
78            Environment::Production => format!("{}{}", MPESA_PRODUCTION_API_URL, path)
79        }
80    }
81
82    fn api_url(&self) -> &str {
83        &self.api_url
84    }
85
86    fn access_token(&self) -> &str {
87        &self.access_token
88    }
89}