1#![forbid(unsafe_code)]
2#![deny(dead_code)]
3#![deny(unused_must_use)]
4#![deny(clippy::all)]
5#![deny(clippy::pedantic)]
6#![deny(clippy::unwrap_used)]
7#![deny(clippy::panic)]
8#![deny(clippy::perf)]
9#![deny(clippy::nursery)]
10#![deny(clippy::needless_update)]
11#![deny(clippy::match_like_matches_macro)]
12#![deny(clippy::from_over_into)]
13#![deny(clippy::useless_conversion)]
14#![allow(clippy::module_name_repetitions)]
15#![allow(clippy::missing_errors_doc)]
16#![allow(clippy::upper_case_acronyms)]
17
18mod error;
19pub mod types;
20
21use crate::{
22 error::Result,
23 types::{ResponseFriends, ResponsePicture, User},
24};
25use async_trait::async_trait;
26use hyper::{body, Body, Client, Request};
27use hyper_tls::HttpsConnector;
28
29#[async_trait]
30pub trait GraphAPI {
31 async fn me(&self, token: &str) -> Result<User>;
32 async fn friends(&self, token: &str) -> Result<ResponseFriends>;
33 async fn my_picture(&self, token: &str) -> Result<ResponsePicture>;
34}
35
36#[derive(Default, Debug)]
37pub struct FBGraphAPI {}
38
39const BASE_URL: &str = "https://graph.facebook.com/v8.0";
40
41#[async_trait]
42impl GraphAPI for FBGraphAPI {
43 async fn me(&self, token: &str) -> Result<User> {
44 let url = format!(
45 "{}/me?fields=id%2Cname%2Cfirst_name%2Clast_name%2Cemail&access_token={}",
46 BASE_URL, token
47 );
48
49 let resp = get_request(&url).await?;
50 let resp: User = serde_json::from_str(&resp)?;
51
52 Ok(resp)
53 }
54
55 async fn friends(&self, token: &str) -> Result<ResponseFriends> {
56 let url = format!(
57 "{}/me/friends?fields=id%2Cname%2Cfirst_name%2Clast_name&access_token={}",
58 BASE_URL, token
59 );
60
61 let resp = get_request(&url).await?;
62 let resp: ResponseFriends = serde_json::from_str(&resp)?;
63
64 Ok(resp)
65 }
66
67 async fn my_picture(&self, token: &str) -> Result<ResponsePicture> {
68 let url = format!(
69 "{}/me/picture?redirect=false&access_token={}",
70 BASE_URL, token
71 );
72
73 let resp = get_request(&url).await?;
74 let resp: ResponsePicture = serde_json::from_str(&resp)?;
75
76 Ok(resp)
77 }
78}
79
80async fn get_request(url: &str) -> Result<String> {
81 let client = Client::builder().build::<_, Body>(HttpsConnector::new());
82 let request = Request::builder()
83 .method("GET")
84 .uri(url)
85 .body(Body::empty())?;
86 let response = client.request(request).await?;
87
88 let buf = body::to_bytes(response).await?;
89 let res = String::from_utf8(buf.to_vec())?;
90
91 Ok(res)
92}