diff --git a/Cargo.toml b/Cargo.toml index e8091fa..fb684cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,4 +17,4 @@ hyper-tls = "0.5.0" reqwest = { version = "0.11.18", features = ["json", "blocking"] } serde = { version = "1.0.180", features = ["derive"] } serde_json = "1.0.104" -serde_qs = "0.12" +serde_urlencoded = "0.7.1" diff --git a/src/api/autocomplete.rs b/src/api/autocomplete.rs index 490231a..0594e3e 100644 --- a/src/api/autocomplete.rs +++ b/src/api/autocomplete.rs @@ -19,12 +19,8 @@ impl Autocomplete { params: AutocompleteParams, ) -> Result { params.validate()?; - let qs = serde_qs::to_string(¶ms).map_err(|_| PDLError::ValidationError)?; - let r = self - .client - .get::(AUTOCOMPLETE_PATH, &qs)?; - - Ok(r) + self.client + .get::(AUTOCOMPLETE_PATH, params) } } diff --git a/src/api/company.rs b/src/api/company.rs index 2fcb6a4..093a11e 100644 --- a/src/api/company.rs +++ b/src/api/company.rs @@ -22,10 +22,8 @@ impl Company { /// docs: https://docs.peopledatalabs.com/docs/company-enrichment-api pub fn enrich(&self, params: EnrichCompanyParams) -> Result { params.validate()?; - let qs = serde_qs::to_string(¶ms).map_err(|_| PDLError::ValidationError)?; - let r = self.client.get::(ENRICH_PATH, &qs)?; - - Ok(r) + self.client + .get::(ENRICH_PATH, params) } /// Search gives you access to every record in our full Company dataset, @@ -33,20 +31,16 @@ impl Company { /// docs: https://docs.peopledatalabs.com/docs/company-search-api pub fn search(&self, params: SearchParams) -> Result { params.validate()?; - let qs = serde_qs::to_string(¶ms).map_err(|_| PDLError::ValidationError)?; - let r = self.client.get::(SEARCH_PATH, &qs)?; - - Ok(r) + self.client + .get::(SEARCH_PATH, params) } /// Clean your company data, so you can better query our person data /// docs: https://docs.peopledatalabs.com/docs/cleaner-apis-reference pub fn clean(&self, params: CleanCompanyParams) -> Result { params.validate()?; - let qs = serde_qs::to_string(¶ms).map_err(|_| PDLError::ValidationError)?; - let r = self.client.get::(CLEAN_PATH, &qs)?; - - Ok(r) + self.client + .get::(CLEAN_PATH, params) } } diff --git a/src/api/ip.rs b/src/api/ip.rs index c1ed62b..86d018d 100644 --- a/src/api/ip.rs +++ b/src/api/ip.rs @@ -12,10 +12,7 @@ pub struct IP { impl IP { pub fn get(&self, params: IPParams) -> Result { params.validate()?; - let qs = serde_qs::to_string(¶ms).map_err(|_| PDLError::ValidationError)?; - let r = self.client.get::(PATH, &qs)?; - - Ok(r) + self.client.get::(PATH, params) } } diff --git a/src/api/jobtitle.rs b/src/api/jobtitle.rs index 8735993..129d813 100644 --- a/src/api/jobtitle.rs +++ b/src/api/jobtitle.rs @@ -12,10 +12,8 @@ pub struct JobTitle { impl JobTitle { pub fn get(&self, params: JobTitleParams) -> Result { params.validate()?; - let qs = serde_qs::to_string(¶ms).map_err(|_| PDLError::ValidationError)?; - let r = self.client.get::(PATH, &qs)?; - - Ok(r) + self.client + .get::(PATH, params) } } diff --git a/src/api/location.rs b/src/api/location.rs index 4469e9c..0d7cdaf 100644 --- a/src/api/location.rs +++ b/src/api/location.rs @@ -12,10 +12,8 @@ pub struct Location { impl Location { pub fn clean(&self, params: CleanLocationParams) -> Result { params.validate()?; - let qs = serde_qs::to_string(¶ms).map_err(|_| PDLError::ValidationError)?; - let r = self.client.get::(PATH, &qs)?; - - Ok(r) + self.client + .get::(PATH, params) } } diff --git a/src/api/person.rs b/src/api/person.rs index e7c0386..c7d112f 100644 --- a/src/api/person.rs +++ b/src/api/person.rs @@ -25,25 +25,19 @@ pub struct Person { impl Person { pub fn enrich(&self, params: EnrichPersonParams) -> Result { params.validate()?; - let qs = serde_qs::to_string(¶ms).map_err(|_| PDLError::ValidationError)?; - dbg!(&qs); - let r = self - .client - .get::(PERSON_ENRICH_PATH, &qs)?; - - Ok(r) + self.client + .get::(PERSON_ENRICH_PATH, params) } pub fn bulk_enrich( &self, params: BulkEnrichPersonParams, ) -> Result, PDLError> { - let json = serde_json::to_value(params).map_err(|_| PDLError::ValidationError)?; - let r = self - .client - .post::>(PERSON_BULK_ENRICH_PATH, json)?; - - Ok(r) + self.client + .post::, BulkEnrichPersonParams>( + PERSON_BULK_ENRICH_PATH, + params, + ) } pub fn identify( @@ -51,22 +45,14 @@ impl Person { params: IdentifyPersonParams, ) -> Result { params.validate()?; - let qs = serde_qs::to_string(¶ms).map_err(|_| PDLError::ValidationError)?; - let r = self - .client - .get::(PERSON_IDENTIFY_PATH, &qs)?; - - Ok(r) + self.client + .get::(PERSON_IDENTIFY_PATH, params) } pub fn search(&self, params: SearchParams) -> Result { params.validate()?; - let qs = serde_qs::to_string(¶ms).map_err(|_| PDLError::ValidationError)?; - let r = self - .client - .get::(PERSON_SEARCH_PATH, &qs)?; - - Ok(r) + self.client + .get::(PERSON_SEARCH_PATH, params) } pub fn retrieve( @@ -74,23 +60,20 @@ impl Person { params: RetrievePersonParams, ) -> Result { params.validate()?; - let qs = serde_qs::to_string(¶ms).map_err(|_| PDLError::ValidationError)?; let url = PERSON_RETRIEVE_PATH.to_string() + ¶ms.person_id; - let r = self.client.get::(&url, &qs)?; - - Ok(r) + self.client + .get::(&url, params) } pub fn bulk_retrieve( &self, params: BulkRetrievePersonParams, ) -> Result, PDLError> { - let json = serde_json::to_value(params).map_err(|_| PDLError::ValidationError)?; - let r = self - .client - .post::>(PERSON_BULK_RETRIEVE_PATH, json)?; - - Ok(r) + self.client + .post::, BulkRetrievePersonParams>( + PERSON_BULK_RETRIEVE_PATH, + params, + ) } } diff --git a/src/api/school.rs b/src/api/school.rs index 8dabd7c..bf0fbc9 100644 --- a/src/api/school.rs +++ b/src/api/school.rs @@ -12,10 +12,8 @@ pub struct School { impl School { pub fn clean(&self, params: CleanSchoolParams) -> Result { params.validate()?; - let qs = serde_qs::to_string(¶ms).map_err(|_| PDLError::ValidationError)?; - let r = self.client.get::(PATH, &qs)?; - - Ok(r) + self.client + .get::(PATH, params) } } diff --git a/src/api/skills.rs b/src/api/skills.rs index 638fbf8..a490aac 100644 --- a/src/api/skills.rs +++ b/src/api/skills.rs @@ -12,10 +12,7 @@ pub struct Skill { impl Skill { pub fn get(&self, params: SkillParams) -> Result { params.validate()?; - let qs = serde_qs::to_string(¶ms).map_err(|_| PDLError::ValidationError)?; - let r = self.client.get::(PATH, &qs)?; - - Ok(r) + self.client.get::(PATH, params) } } diff --git a/src/client.rs b/src/client.rs index d688572..eb2456c 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,4 +1,8 @@ +use reqwest::blocking as rq; +use reqwest::header; use reqwest::StatusCode; +use serde::de::DeserializeOwned; +use serde::Serialize; use std::error::Error; use std::fmt::{self, Display, Formatter}; use std::time::Duration; @@ -14,6 +18,7 @@ static DEFAULT_TIMEOUT: Duration = Duration::from_secs(10); pub enum PDLError { NetworkError(reqwest::Error), HTTPError(StatusCode), + SerializationError, ValidationError, } @@ -22,7 +27,8 @@ impl Display for PDLError { match *self { PDLError::NetworkError(ref e) => e.fmt(f), PDLError::HTTPError(ref s) => write!(f, "Invalid HTTP status code: {}", s), - PDLError::ValidationError => f.write_str("Invalid Parameters"), + PDLError::SerializationError => f.write_str("Unable to serialize."), + PDLError::ValidationError => f.write_str("Unable to validate."), } } } @@ -51,24 +57,31 @@ pub struct PDLClient { api_key: String, base_url: String, api_version: String, - client: reqwest::blocking::Client, + client: rq::Client, } -impl PDLClient { - /// Make a new People Data Labs client with users API Key and API Version. - pub fn new(key: &str) -> PDLClient { - // Sets the default PDLClient - use reqwest::blocking as rq; +/// Builds client based off of API_KEY and Optional Timeout +fn build_client(api_key: &str, timeout: Option) -> rq::Client { + let mut headers = header::HeaderMap::new(); + let api_key = header::HeaderValue::from_str(api_key).unwrap(); + headers.insert("X-Api-Key", api_key); + + let duration = timeout.unwrap_or(DEFAULT_TIMEOUT); - let builder = rq::ClientBuilder::new(); - let client = builder - .user_agent(APP_USER_AGENT) - .timeout(DEFAULT_TIMEOUT) - .build() - .unwrap(); + rq::Client::builder() + .default_headers(headers) + .user_agent(APP_USER_AGENT) + .timeout(duration) + .build() + .expect("Failed to build reqwest client") +} +impl PDLClient { + /// Make a new People Data Labs client with users API Key and API Version. + pub fn new(api_key: &str) -> Self { + let client = build_client(api_key, None); PDLClient { - api_key: key.to_string(), + api_key: api_key.to_string(), base_url: DEFAULT_API_URL.to_string(), api_version: DEFAULT_API_VERSION.to_string(), client, @@ -76,24 +89,16 @@ impl PDLClient { } /// Adds the ability to update the version from the default through chaining. - pub fn version(mut self, version: &str) -> PDLClient { + pub fn version(mut self, version: &str) -> Self { self.api_version = version.to_string(); self } /// Adds the ability to update the default timeout or access sandbox mode /// through chaining. - pub fn options(mut self, options: PDLCLientOptions) -> PDLClient { + pub fn options(mut self, options: PDLCLientOptions) -> Self { if options.timeout != DEFAULT_TIMEOUT { - use reqwest::blocking as rq; - - let builder = rq::ClientBuilder::new(); - let client = builder - .user_agent(APP_USER_AGENT) - .timeout(options.timeout) - .build() - .unwrap(); - self.client = client + self.client = build_client(&self.api_key, Some(options.timeout)) } if options.sandbox { @@ -115,23 +120,24 @@ impl PDLClient { /// Sends a GET method through the PeopleDataLabs API. It takes an endpoint &str and params &str. /// It returns a generic response or PDLError. - pub fn get(&self, endpoint: &str, params: &str) -> Result + pub fn get(&self, endpoint: &str, params: P) -> Result where - T: serde::de::DeserializeOwned, + T: DeserializeOwned, + P: Serialize, { + let query_params = + serde_urlencoded::to_string(params).map_err(|_| PDLError::SerializationError)?; + let uri = format!( - "{}{}{}?api_key={}&{}", - self.base_url, self.api_version, endpoint, self.api_key, params + "{}{}{}?{}", + self.base_url, self.api_version, endpoint, query_params ); - dbg!(&uri); - let resp = self .client .get(uri) .send() - .map_err(PDLError::NetworkError) - .unwrap(); + .map_err(PDLError::NetworkError)?; match resp.status() { StatusCode::OK => {} @@ -139,40 +145,32 @@ impl PDLClient { other => return Err(PDLError::HTTPError(other)), } - let r = resp.json::().unwrap(); - - Ok(r) + resp.json::().map_err(PDLError::NetworkError) } /// Sends a POST method through the PeopleDataLabs API. It takes an endpoint &str and params &str. /// It returns a generic response or PDLError. - pub fn post(&self, endpoint: &str, json: serde_json::Value) -> Result + pub fn post(&self, endpoint: &str, params: P) -> Result where - T: serde::de::DeserializeOwned + std::fmt::Debug, + T: DeserializeOwned, + P: Serialize, { - let uri = format!( - "{}{}{}?api_key={}", - self.base_url, self.api_version, endpoint, self.api_key - ); + let json = serde_json::to_value(params).map_err(|_| PDLError::ValidationError)?; - dbg!(&uri); - dbg!(&json); + let uri = format!("{}{}{}", self.base_url, self.api_version, endpoint); let resp = self .client .post(uri) .json(&json) .send() - .map_err(PDLError::NetworkError) - .unwrap(); + .map_err(PDLError::NetworkError)?; match resp.status() { StatusCode::OK => {} other => return Err(PDLError::HTTPError(other)), } - let r = resp.json::().unwrap(); - - Ok(r) + resp.json::().map_err(PDLError::NetworkError) } }