facebook_access_token_api/endpoints/
access_token.rs

1//! [Ref](https://developers.facebook.com/docs/facebook-login/guides/access-tokens/get-long-lived#get-a-long-lived-user-access-token)
2
3use http_api_client_endpoint::{
4    http::{
5        header::{ACCEPT, USER_AGENT},
6        Method, StatusCode,
7    },
8    Body, Endpoint, Request, Response, MIME_APPLICATION_JSON,
9};
10use serde::{Deserialize, Serialize};
11use url::Url;
12
13use crate::{
14    endpoints::{
15        common::{EndpointError, EndpointRet},
16        URL_BASE, VERSION,
17    },
18    objects::ResponseBodyErrJson,
19};
20
21//
22#[derive(Debug, Clone)]
23pub struct AccessTokenEndpoint {
24    pub grant_type: Box<str>,
25    pub app_id: u64,
26    pub app_secret: Option<Box<str>>,
27    pub fb_exchange_token: Option<Box<str>>,
28    //
29    pub version: Option<Box<str>>,
30}
31
32impl AccessTokenEndpoint {
33    pub fn new(
34        grant_type: impl AsRef<str>,
35        app_id: u64,
36        app_secret: impl Into<Option<Box<str>>>,
37        fb_exchange_token: impl Into<Option<Box<str>>>,
38        version: impl Into<Option<Box<str>>>,
39    ) -> Self {
40        Self {
41            grant_type: grant_type.as_ref().into(),
42            app_id,
43            app_secret: app_secret.into(),
44            fb_exchange_token: fb_exchange_token.into(),
45            version: version.into(),
46        }
47    }
48}
49
50impl Endpoint for AccessTokenEndpoint {
51    type RenderRequestError = EndpointError;
52
53    type ParseResponseOutput = EndpointRet<AccessTokenResponseBodyOkJson>;
54    type ParseResponseError = EndpointError;
55
56    fn render_request(&self) -> Result<Request<Body>, Self::RenderRequestError> {
57        let url = format!(
58            "{}/{}/oauth/access_token",
59            URL_BASE,
60            self.version.as_deref().unwrap_or(VERSION),
61        );
62        let mut url = Url::parse(&url).map_err(EndpointError::MakeRequestUrlFailed)?;
63
64        url.query_pairs_mut()
65            .append_pair("grant_type", &self.grant_type);
66
67        url.query_pairs_mut()
68            .append_pair("client_id", &self.app_id.to_string());
69
70        if let Some(client_secret) = &self.app_secret {
71            url.query_pairs_mut()
72                .append_pair("client_secret", client_secret);
73        }
74
75        if let Some(fb_exchange_token) = &self.fb_exchange_token {
76            url.query_pairs_mut()
77                .append_pair("fb_exchange_token", fb_exchange_token);
78        }
79
80        let request = Request::builder()
81            .method(Method::GET)
82            .uri(url.as_str())
83            .header(USER_AGENT, "facebook-access-token-api")
84            .header(ACCEPT, MIME_APPLICATION_JSON)
85            .body(vec![])
86            .map_err(EndpointError::MakeRequestFailed)?;
87
88        Ok(request)
89    }
90
91    fn parse_response(
92        &self,
93        response: Response<Body>,
94    ) -> Result<Self::ParseResponseOutput, Self::ParseResponseError> {
95        let status = response.status();
96        match status {
97            StatusCode::OK => Ok(EndpointRet::Ok(
98                serde_json::from_slice(response.body())
99                    .map_err(EndpointError::DeResponseBodyOkJsonFailed)?,
100            )),
101            status => match serde_json::from_slice::<ResponseBodyErrJson>(response.body()) {
102                Ok(err_json) => Ok(EndpointRet::Other((status, Ok(err_json)))),
103                Err(_) => Ok(EndpointRet::Other((
104                    status,
105                    Err(response.body().to_owned()),
106                ))),
107            },
108        }
109    }
110}
111
112//
113//
114//
115#[derive(Deserialize, Serialize, Debug, Clone)]
116pub struct AccessTokenResponseBodyOkJson {
117    pub access_token: String,
118    pub token_type: String,
119    pub expires_in: Option<usize>,
120}