facebook_graph_api_explorer_kit/
path_and_query.rs1use url::{ParseError as UrlParseError, Url};
2
3const PREFIX: &str = "https://graph.facebook.com/v11.0";
4
5pub fn parse<'a>(path_and_query: &str, node_type: Option<&'a str>) -> Result<Root<'a>, ParseError> {
6 let url = if path_and_query.is_empty() {
7 return Err(ParseError::PathInvalid("IsEmpty"));
8 } else if path_and_query.starts_with('/') {
9 return Err(ParseError::PathInvalid("IsStartsWithSlash"));
10 } else {
11 format!("{}/{}", PREFIX, path_and_query)
12 };
13 let mut url = Url::parse(&url)?;
14 let path = url.path().to_owned();
15 if path.ends_with('/') {
16 url.set_path(&path[..path.len() - 1]);
17 }
18 let mut path_segments = url.path_segments().expect("");
19 debug_assert_eq!(path_segments.next(), Some("v11.0"));
20 let mut _query_pairs = url.query_pairs();
21
22 let root = path_segments.next().ok_or(ParseError::RootMissing)?;
23 let mut root = if let Ok(_node_id) = root.parse::<u64>() {
24 let node_type = node_type.ok_or(ParseError::NodeTypeMissing)?;
25 Root::Node(node_type, None)
26 } else {
27 match root {
28 "me" => Root::Node("User", None),
29 "ig_hashtag_search" => Root::Edge(root.to_owned()),
30 _ => return Err(ParseError::RootIsUnknown),
31 }
32 };
33 match root {
34 Root::Node(node_type, _) => {
35 if let Some(edge) = path_segments.next() {
36 root = Root::Node(node_type, Some(edge.to_owned()))
37 }
38 if path_segments.next().is_some() {
39 return Err(ParseError::PathInvalid("TODO"));
40 }
41 }
42 Root::Edge(_) => {
43 if path_segments.next().is_some() {
44 return Err(ParseError::PathInvalid("TODO"));
45 }
46 }
47 }
48
49 Ok(root)
50}
51
52#[derive(PartialEq, Eq, Debug, Clone)]
53pub enum Root<'a> {
54 Node(&'a str, Option<String>),
55 Edge(String),
56}
57
58#[derive(thiserror::Error, Debug)]
59pub enum ParseError {
60 #[error("PathInvalid {0}")]
61 PathInvalid(&'static str),
62 #[error("PathOrQueryInvalid {0}")]
63 PathOrQueryInvalid(#[from] UrlParseError),
64 #[error("RootMissing")]
65 RootMissing,
66 #[error("RootIsUnknown")]
67 RootIsUnknown,
68 #[error("NodeTypeMissing")]
69 NodeTypeMissing,
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 #[test]
77 fn test_parse() {
78 match parse("", None) {
79 Err(ParseError::PathInvalid(_)) => {}
80 err => panic!("{:?}", err),
81 }
82 match parse("/", None) {
83 Err(ParseError::PathInvalid(_)) => {}
84 err => panic!("{:?}", err),
85 }
86
87 match parse("foo", None) {
88 Err(ParseError::RootIsUnknown) => {}
89 err => panic!("{:?}", err),
90 }
91
92 match parse("me", None) {
93 Ok(root) => assert_eq!(root, Root::Node("User", None)),
94 err => panic!("{:?}", err),
95 }
96 match parse("780170842505209", Some("User")) {
97 Ok(root) => assert_eq!(root, Root::Node("User", None)),
98 err => panic!("{:?}", err),
99 }
100 match parse("me?fields=id,name", None) {
101 Ok(root) => assert_eq!(root, Root::Node("User", None)),
102 err => panic!("{:?}", err),
103 }
104 match parse("me/accounts", None) {
105 Ok(root) => assert_eq!(root, Root::Node("User", Some("accounts".to_owned()))),
106 err => panic!("{:?}", err),
107 }
108 match parse("me/accounts?fields=id,name", None) {
109 Ok(root) => assert_eq!(root, Root::Node("User", Some("accounts".to_owned()))),
110 err => panic!("{:?}", err),
111 }
112 match parse("me/accounts/foo", None) {
113 Err(ParseError::PathInvalid(_)) => {}
114 err => panic!("{:?}", err),
115 }
116
117 match parse(
118 "ig_hashtag_search?user_id=17841406427775093&q=bluebottle",
119 None,
120 ) {
121 Ok(root) => assert_eq!(root, Root::Edge("ig_hashtag_search".to_owned())),
122 err => panic!("{:?}", err),
123 }
124 match parse("ig_hashtag_search/foo", None) {
125 Err(ParseError::PathInvalid(_)) => {}
126 err => panic!("{:?}", err),
127 }
128 }
129}