1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
//! GitHub API V4 queries and mutations.

use crate::api::handle_graphql_response;
use crate::error::TelescopeError;
use crate::web::telescope_ua;
use graphql_client::{GraphQLQuery, Response as GraphQLResponse};
use oauth2::AccessToken;
use reqwest::header::{HeaderValue, ACCEPT, USER_AGENT};
use reqwest::Client;

pub mod users;

/// The GitHub API endpoint
const GITHUB_API_ENDPOINT: &'static str = "https://api.github.com/graphql";

/// The name of this API in error reporting.
const API_NAME: &'static str = "GitHub API V4";

/// Send a GraphQL query to the GitHub API.
pub async fn send_query<T: GraphQLQuery>(
    auth_token: &AccessToken,
    variables: T::Variables,
) -> Result<T::ResponseData, TelescopeError> {
    // Build GraphQL request
    let query = T::build_query(variables);

    // Make a client, send the request, and return the result.
    return Client::new()
        // POST request to the GitHub GraphQL API endpoint
        .post(GITHUB_API_ENDPOINT)
        // With the JSON of the GraphQL query
        .json(&query)
        // With the user's access token
        .bearer_auth(auth_token.secret())
        // And required headers
        .header(ACCEPT, HeaderValue::from_static("application/json"))
        .header(USER_AGENT, telescope_ua())
        // Send and wait for a response
        .send()
        .await
        // Propagate any errors sending or receiving
        .map_err(TelescopeError::github_api_error)?
        // Get response as string
        .text()
        // Wait to receive the full response
        .await
        // Convert any errors.
        .map_err(TelescopeError::github_api_error)
        // Convert the valid JSON value into the GraphQL response type.
        .and_then(|body| {
            serde_json::from_str::<GraphQLResponse<T::ResponseData>>(body.as_str())
                // Convert serde error to telescope error
                .map_err(|err| {
                    // Log the error and response body
                    error!(
                        "Malformed GitHub API response: {}\nresponse body: {}",
                        err,
                        body.as_str()
                    );
                    // Convert error.
                    TelescopeError::GitHubApiError(err.to_string())
                })
        })
        // Convert any errors in the response
        .and_then(|response| handle_graphql_response(API_NAME, response));
}