usps_api/
lib.rs

1//! # USPS WebTools
2//! A Rust library for interfacing with the USPS Web API 
3#![deny(missing_docs,
4        missing_debug_implementations, missing_copy_implementations,
5        trivial_casts, trivial_numeric_casts,
6        unstable_features, unsafe_code,
7        unused_import_braces, unused_qualifications)]
8
9/* Standard Libary */
10use std::env;
11
12/* Third Party Libraries */
13use reqwest;
14use roxmltree;
15
16/* Modules */
17pub mod address;
18
19/* Static Strings */
20const SECURE_ENDPOINT:   &'static str = "https://secure.shippingapis.com/ShippingAPI.dll?API=";
21const UNSECURE_ENDPOINT: &'static str = "http://production.shippingapis.com/ShippingAPI.dll?API=";
22
23const ENV_USER_ID: &'static str = "USPS_USER_ID";
24const ENV_PASSWORD: &'static str = "USPS_PASSWORD";
25
26/// This struct is how you will make API calls to the USPS. It can be initialized with a hardcoded user_id and password using the 'init' contructor or it can attempt to capture these values from the environment (USPS_USER_ID and USPS_PASSWORD respectively) using the 'new' constructor.
27#[derive(Debug, PartialEq)]
28pub struct USPSWebTool {
29    secure: bool,
30    user_id: String,
31    password: String,
32}
33
34/* Constructor and Setter Implementations */
35impl USPSWebTool {
36    /// Used to build a new USPSWebTool struct by specifying the USPS authentication credentials directly."
37	/// # Example
38	/// ```
39	/// # use usps_api::USPSWebTool;
40    /// let usps_api = USPSWebTool::init("XXXX", "YYYY");
41	/// ```
42    pub fn init(user_id: &str, password: &str) -> Self {
43        USPSWebTool {
44            secure: true,
45            user_id: String::from(user_id),
46            password: String::from(password)
47        }
48    }
49
50    /// Used to build a new USPSWebTool struct by looking at the environment variables "USPS_USER_ID" and "USPS_PASSWORD to specify the USPS authentication credentials." 
51	/// # Example
52	/// ```
53	/// # use usps_api::USPSWebTool;
54    /// # use std::env;
55    /// # fn main() -> Result<(), env::VarError> {
56    /// env::set_var("USPS_USER_ID", "XXXX");
57    /// env::set_var("USPS_PASSWORD", "YYYY");
58    /// let usps_api = USPSWebTool::new()?;
59    /// # Ok(())
60    /// # }
61	/// ```
62    pub fn new() -> Result<Self, env::VarError> {
63        let user_id = env::var(ENV_USER_ID)?;
64        let password = env::var(ENV_PASSWORD)?;
65
66        Ok(USPSWebTool {
67            secure: true,
68            user_id,
69            password,
70        })
71    }
72
73    /* Disables security */
74    /// Will use the unsecured endpoint for communication with the USPS API. This feature is **not** recommended.
75    ///
76	/// # Example
77	/// ```
78	/// # use usps_api::USPSWebTool;
79    /// let usps_api = USPSWebTool::init("XXXX", "YYYY").use_http();
80	/// ```
81    pub fn use_http(mut self) -> Self {
82       self.secure = false;
83       self
84    }
85
86    /// Accepts a USPS Address and returns a result with the 'correct' form of the address.
87    pub fn verify_address(&self, address: address::USPSAddress) -> Result<address::USPSAddress, Box<dyn std::error::Error>> {
88        let mut req;
89        if self.secure {
90            req = String::from(SECURE_ENDPOINT);
91        } else {
92            req = String::from(UNSECURE_ENDPOINT);
93        }
94        
95        /* Construct the query URL */
96        req.push_str("Verify&XML=");
97        req.push_str(&format!("<AddressValidateRequest USERID=\"{}\"><Revision>1</Revision>", self.user_id));
98        req.push_str(&address.xml());
99        req.push_str("</AddressValidateRequest>"); 
100        
101        /* Fetch the result */
102        let body = reqwest::get(&req)?.text()?;
103        println!("{:?}", body);
104
105        /* Check if the XML is an error */
106        let xml = roxmltree::Document::parse(&body)?;
107        /* if xml.root_element().tag_name().name() == "Error" { */ 
108        /* } */
109        
110        Ok(address::USPSAddress::from_xml(xml))
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117
118    const DUMMY_UN: &'static str = "USERNAME";
119    const DUMMY_PW: &'static str = "PASSWORD";
120
121    #[test]
122    fn init_constructor() {
123        let dummy_struct = USPSWebTool {
124            secure: true,
125            user_id: String::from(DUMMY_UN), 
126            password: String::from(DUMMY_PW),
127        };
128
129        assert_eq!(USPSWebTool::init(DUMMY_UN, DUMMY_PW), dummy_struct);
130    }
131
132    #[test]
133    fn new_constructor() {
134        env::set_var(ENV_USER_ID, DUMMY_UN);
135        env::set_var(ENV_PASSWORD, DUMMY_PW);
136
137        let dummy_struct = USPSWebTool {
138            secure: true,
139            user_id: String::from(DUMMY_UN), 
140            password: String::from(DUMMY_PW),
141        };
142
143        assert_eq!(USPSWebTool::new().unwrap(), dummy_struct);
144    }
145
146    #[test]
147    #[should_panic]
148    fn new_contructor_no_env() {
149        env::remove_var(ENV_USER_ID);
150        env::remove_var(ENV_PASSWORD);
151
152        let dummy_struct = USPSWebTool {
153            secure: true,
154            user_id: String::from(DUMMY_UN), 
155            password: String::from(DUMMY_PW),
156        };
157
158        assert_eq!(USPSWebTool::new().unwrap(), dummy_struct);
159    }
160
161    #[test]
162    fn use_http() {
163        let dummy_struct = USPSWebTool {
164            secure: false,
165            user_id: String::from(DUMMY_UN), 
166            password: String::from(DUMMY_PW),
167        };
168
169        assert_eq!(USPSWebTool::init(DUMMY_UN, DUMMY_PW).use_http(), 
170                   dummy_struct);
171    }
172
173    mod address_test {
174        use super::*;
175
176        #[test]
177        fn test_address_1() {
178
179            let api = USPSWebTool::init("348XVRQT1293", "088NI00MI876");
180            let home = address::USPSAddress::quick("429 2nd Ave W", "104", "Seattle", "WA", "98119");
181            api.verify_address(home).unwrap();
182            
183
184        }
185    }
186}
187