Skip to main content

asimov_apify_module/api/
linkedin.rs

1// This is free and unencumbered software released into the public domain.
2
3#![allow(unused)]
4
5use asimov_module::prelude::{FromStr, String, ToString};
6use serde::Serialize;
7use url::{ParseError, Url};
8
9/// See: https://apify.com/apimaestro/linkedin-profile-detail
10#[derive(Clone, Debug, Default, Serialize)]
11pub struct LinkedInProfileScrapeRequest {
12    pub username: String,
13}
14
15impl FromStr for LinkedInProfileScrapeRequest {
16    type Err = ParseError;
17
18    fn from_str(input: &str) -> Result<Self, Self::Err> {
19        let url = Url::parse(input)?;
20        let username = url
21            .path_segments()
22            .and_then(|mut segments| segments.nth(1)) // Skip "in" to get username
23            .filter(|s| !s.is_empty())
24            .ok_or(ParseError::InvalidDomainCharacter)?
25            .to_string();
26        // Reject extra segments (e.g., /in/username/extra)
27        if url.path_segments().map(|segments| segments.count()).unwrap_or(0) > 2 {
28            return Err(ParseError::InvalidDomainCharacter);
29        }
30        Ok(Self { username })
31    }
32}
33
34#[cfg(test)]
35mod tests {
36    use super::*;
37
38    #[test]
39    fn test_from_str() {
40        let request = LinkedInProfileScrapeRequest::from_str("https://www.linkedin.com/in/johndoe").unwrap();
41        assert_eq!(request.username, "johndoe");
42        assert!(LinkedInProfileScrapeRequest::from_str("https://www.linkedin.com/in/").is_err());
43        assert!(LinkedInProfileScrapeRequest::from_str("https://www.linkedin.com/in/johndoe/extra").is_err());
44        assert!(LinkedInProfileScrapeRequest::from_str("invalid").is_err());
45    }
46}