fb_api/
lib.rs

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}