From 0cb8e613cb430dc9ea1ee5aab6052af4a0b1afeb Mon Sep 17 00:00:00 2001 From: Jacob McKenzie Date: Fri, 7 Nov 2025 12:44:45 -0700 Subject: [PATCH 1/2] Add support for international postal code api --- Makefile | 7 +- smarty-rust-sdk/Cargo.toml | 3 + .../examples/international_postal_code_api.rs | 38 +++++++++ .../candidate.rs | 18 +++++ .../international_postal_code_api/client.rs | 17 ++++ .../international_postal_code_api/lookup.rs | 28 +++++++ .../src/international_postal_code_api/mod.rs | 79 +++++++++++++++++++ smarty-rust-sdk/src/lib.rs | 1 + smarty-rust-sdk/src/sdk/client.rs | 4 +- 9 files changed, 191 insertions(+), 4 deletions(-) create mode 100644 smarty-rust-sdk/examples/international_postal_code_api.rs create mode 100644 smarty-rust-sdk/src/international_postal_code_api/candidate.rs create mode 100644 smarty-rust-sdk/src/international_postal_code_api/client.rs create mode 100644 smarty-rust-sdk/src/international_postal_code_api/lookup.rs create mode 100644 smarty-rust-sdk/src/international_postal_code_api/mod.rs diff --git a/Makefile b/Makefile index c60a7c3..49a8a19 100644 --- a/Makefile +++ b/Makefile @@ -26,6 +26,9 @@ clippy: international_autocomplete_api: RUST_LOG=trace cargo run --example international_autocomplete_api +international_postal_code_api: + RUST_LOG=trace cargo run --example international_postal_code_api + international_street_api: RUST_LOG=trace cargo run --example international_street_api @@ -50,6 +53,6 @@ us_zipcode_api: us_enrichment_api: RUST_LOG=trace cargo run --example us_enrichment_api -examples: international_autocomplete_api international_street_api logger us_autocomplete_pro_api us_extract_api us_reverse_geo_api us_street_api us_zipcode_api +examples: international_autocomplete_api international_postal_code_api international_street_api logger us_autocomplete_pro_api us_extract_api us_reverse_geo_api us_street_api us_zipcode_api -.PHONY: clean test dependencies package examples clippy international_autocomplete_api international_street_api logger us_autocomplete_pro_api us_extract_api us_reverse_geo_api us_street_api us_zipcode_api us_enrichment_api +.PHONY: clean test dependencies package examples clippy international_autocomplete_api international_postal_code_api international_street_api logger us_autocomplete_pro_api us_extract_api us_reverse_geo_api us_street_api us_zipcode_api us_enrichment_api diff --git a/smarty-rust-sdk/Cargo.toml b/smarty-rust-sdk/Cargo.toml index 15f8a47..c246c8a 100644 --- a/smarty-rust-sdk/Cargo.toml +++ b/smarty-rust-sdk/Cargo.toml @@ -55,6 +55,9 @@ name = "international_street_api" [[example]] name = "international_autocomplete_api" +[[example]] +name = "international_postal_code_api" + [[example]] name = "logger" diff --git a/smarty-rust-sdk/examples/international_postal_code_api.rs b/smarty-rust-sdk/examples/international_postal_code_api.rs new file mode 100644 index 0000000..d28bc74 --- /dev/null +++ b/smarty-rust-sdk/examples/international_postal_code_api.rs @@ -0,0 +1,38 @@ +extern crate serde_json; +extern crate smarty_rust_sdk; +extern crate tokio; + +use smarty_rust_sdk::international_postal_code_api::client::InternationalPostalCodeClient; +use smarty_rust_sdk::international_postal_code_api::lookup::Lookup; +use smarty_rust_sdk::sdk::authentication::SecretKeyCredential; +use smarty_rust_sdk::sdk::options::OptionsBuilder; +use std::error::Error; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let lookup = &mut Lookup { + input_id: "ID-8675309".to_string(), + locality: "Sao Paulo".to_string(), + administrative_area: "SP".to_string(), + country: "Brazil".to_string(), + postal_code: "02516".to_string(), + ..Default::default() + }; + + let authentication = SecretKeyCredential::new( + std::env::var("SMARTY_AUTH_ID").expect("Missing SMARTY_AUTH_ID env variable"), + std::env::var("SMARTY_AUTH_TOKEN").expect("Missing SMARTY_AUTH_TOKEN env variable"), + ); + + let options = OptionsBuilder::new(Some(authentication)) + .with_logging() + .build(); + + let client = InternationalPostalCodeClient::new(options)?; + + client.send(lookup).await?; + + println!("{}", serde_json::to_string_pretty(&lookup.results)?); + + Ok(()) +} diff --git a/smarty-rust-sdk/src/international_postal_code_api/candidate.rs b/smarty-rust-sdk/src/international_postal_code_api/candidate.rs new file mode 100644 index 0000000..53a6eeb --- /dev/null +++ b/smarty-rust-sdk/src/international_postal_code_api/candidate.rs @@ -0,0 +1,18 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(default)] +pub struct Candidate { + pub input_id: String, + pub administrative_area: String, + pub sub_administrative_area: String, + pub super_administrative_area: String, + pub country_iso_3: String, + pub locality: String, + pub dependent_locality: String, + pub dependent_locality_name: String, + pub double_dependent_locality: String, + #[serde(rename = "postal_code")] + pub postal_code_short: String, + pub postal_code_extra: String, +} diff --git a/smarty-rust-sdk/src/international_postal_code_api/client.rs b/smarty-rust-sdk/src/international_postal_code_api/client.rs new file mode 100644 index 0000000..1bfc0fd --- /dev/null +++ b/smarty-rust-sdk/src/international_postal_code_api/client.rs @@ -0,0 +1,17 @@ +use crate::international_postal_code_api::candidate::Candidate; +use crate::international_postal_code_api::lookup::Lookup; +use crate::sdk::client::Client; +use crate::sdk::error::SmartyError; +use crate::sdk::options::Options; +use crate::sdk::send_request; +use reqwest::Method; +use smarty_rust_proc_macro::smarty_api; + +#[smarty_api( + api_path = "lookup", + default_url = "https://international-postal-code.api.smarty.com/", + lookup_style(lookup), + lookup_type = "Lookup", + result_type = "Vec" +)] +pub struct InternationalPostalCodeClient; diff --git a/smarty-rust-sdk/src/international_postal_code_api/lookup.rs b/smarty-rust-sdk/src/international_postal_code_api/lookup.rs new file mode 100644 index 0000000..65a8da0 --- /dev/null +++ b/smarty-rust-sdk/src/international_postal_code_api/lookup.rs @@ -0,0 +1,28 @@ +use crate::international_postal_code_api::candidate::Candidate; +use crate::sdk::has_param; + +#[derive(Clone, Debug, PartialEq, Default)] +pub struct Lookup { + pub input_id: String, + pub country: String, + pub locality: String, + pub administrative_area: String, + pub postal_code: String, + + pub results: Vec, +} + +impl Lookup { + pub(crate) fn into_param_array(self) -> Vec<(String, String)> { + vec![ + has_param("input_id".to_string(), self.input_id), + has_param("country".to_string(), self.country), + has_param("locality".to_string(), self.locality), + has_param("administrative_area".to_string(), self.administrative_area), + has_param("postal_code".to_string(), self.postal_code), + ] + .into_iter() + .filter_map(std::convert::identity) + .collect() + } +} diff --git a/smarty-rust-sdk/src/international_postal_code_api/mod.rs b/smarty-rust-sdk/src/international_postal_code_api/mod.rs new file mode 100644 index 0000000..6f7bf06 --- /dev/null +++ b/smarty-rust-sdk/src/international_postal_code_api/mod.rs @@ -0,0 +1,79 @@ +pub mod candidate; +pub mod client; +pub mod lookup; + +#[cfg(test)] +mod tests { + use crate::international_postal_code_api::candidate::Candidate; + use crate::international_postal_code_api::client::InternationalPostalCodeClient; + use crate::international_postal_code_api::lookup::Lookup; + use crate::sdk::options::OptionsBuilder; + use serde_json::from_str; + + #[test] + fn client_test() { + let client = InternationalPostalCodeClient::new(OptionsBuilder::new(None).build()).unwrap(); + + assert_eq!( + client.client.url.to_string(), + "https://international-postal-code.api.smarty.com/lookup".to_string() + ); + } + + #[test] + fn lookup_test() { + let lookup = Lookup { + input_id: "ID-8675309".to_string(), + locality: "Sao Paulo".to_string(), + administrative_area: "SP".to_string(), + country: "Brazil".to_string(), + postal_code: "02516".to_string(), + ..Default::default() + }; + + let expected_params = vec![ + ("input_id".to_string(), "ID-8675309".to_string()), + ("country".to_string(), "Brazil".to_string()), + ("locality".to_string(), "Sao Paulo".to_string()), + ("administrative_area".to_string(), "SP".to_string()), + ("postal_code".to_string(), "02516".to_string()), + ]; + + assert_eq!(lookup.into_param_array(), expected_params); + } + + #[test] + fn candidate_test() { + let payload = r#"[ + { + "input_id": "ID-8675309", + "administrative_area": "SP", + "sub_administrative_area": "Greater Sao Paulo", + "super_administrative_area": "Southeast", + "country_iso_3": "BRA", + "locality": "Sao Paulo", + "dependent_locality": "Vila Guilherme", + "dependent_locality_name": "Santana", + "double_dependent_locality": "Zona Norte", + "postal_code": "02516", + "postal_code_extra": "050" + } + ]"#; + + let candidates: Vec = from_str(payload).expect("Failed to deserialize JSON"); + assert_eq!(candidates.len(), 1); + + let candidate = &candidates[0]; + assert_eq!(candidate.input_id, "ID-8675309"); + assert_eq!(candidate.country_iso_3, "BRA"); + assert_eq!(candidate.locality, "Sao Paulo"); + assert_eq!(candidate.dependent_locality, "Vila Guilherme"); + assert_eq!(candidate.dependent_locality_name, "Santana"); + assert_eq!(candidate.double_dependent_locality, "Zona Norte"); + assert_eq!(candidate.administrative_area, "SP"); + assert_eq!(candidate.sub_administrative_area, "Greater Sao Paulo"); + assert_eq!(candidate.super_administrative_area, "Southeast"); + assert_eq!(candidate.postal_code_short, "02516"); + assert_eq!(candidate.postal_code_extra, "050"); + } +} diff --git a/smarty-rust-sdk/src/lib.rs b/smarty-rust-sdk/src/lib.rs index e6520a0..5a6ffa3 100644 --- a/smarty-rust-sdk/src/lib.rs +++ b/smarty-rust-sdk/src/lib.rs @@ -1,4 +1,5 @@ pub mod international_autocomplete_api; +pub mod international_postal_code_api; pub mod international_street_api; pub mod sdk; pub mod us_autocomplete_pro_api; diff --git a/smarty-rust-sdk/src/sdk/client.rs b/smarty-rust-sdk/src/sdk/client.rs index 05b7319..0d4ab17 100644 --- a/smarty-rust-sdk/src/sdk/client.rs +++ b/smarty-rust-sdk/src/sdk/client.rs @@ -54,9 +54,9 @@ impl Client { if let Some(auth) = &self.options.authentication { builder = auth.authenticate(builder); } - + if !self.options.license.is_empty() { - builder = builder.query(&[("license".to_string(), self.options.license.clone())]); + builder = builder.query(&[("license".to_string(), self.options.license.clone())]); } for (header_key, header_value) in self.options.headers.clone() { From d316feaec0b3da7ea1c15fb216c7500e81dffafd Mon Sep 17 00:00:00 2001 From: Jacob McKenzie Date: Fri, 7 Nov 2025 12:47:53 -0700 Subject: [PATCH 2/2] rename --- smarty-rust-sdk/src/international_postal_code_api/candidate.rs | 2 +- smarty-rust-sdk/src/international_postal_code_api/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/smarty-rust-sdk/src/international_postal_code_api/candidate.rs b/smarty-rust-sdk/src/international_postal_code_api/candidate.rs index 53a6eeb..5cdb803 100644 --- a/smarty-rust-sdk/src/international_postal_code_api/candidate.rs +++ b/smarty-rust-sdk/src/international_postal_code_api/candidate.rs @@ -13,6 +13,6 @@ pub struct Candidate { pub dependent_locality_name: String, pub double_dependent_locality: String, #[serde(rename = "postal_code")] - pub postal_code_short: String, + pub postal_code: String, pub postal_code_extra: String, } diff --git a/smarty-rust-sdk/src/international_postal_code_api/mod.rs b/smarty-rust-sdk/src/international_postal_code_api/mod.rs index 6f7bf06..f311e4c 100644 --- a/smarty-rust-sdk/src/international_postal_code_api/mod.rs +++ b/smarty-rust-sdk/src/international_postal_code_api/mod.rs @@ -73,7 +73,7 @@ mod tests { assert_eq!(candidate.administrative_area, "SP"); assert_eq!(candidate.sub_administrative_area, "Greater Sao Paulo"); assert_eq!(candidate.super_administrative_area, "Southeast"); - assert_eq!(candidate.postal_code_short, "02516"); + assert_eq!(candidate.postal_code, "02516"); assert_eq!(candidate.postal_code_extra, "050"); } }