From f282490dc08579780c02477ea45e7f5dcd2239c5 Mon Sep 17 00:00:00 2001 From: Avery Harnish Date: Mon, 21 Jun 2021 11:27:40 -0500 Subject: [PATCH] feat(client): auto-decode gzipped responsesc --- Cargo.lock | 38 +++++++++++++++++++ crates/rover-client/Cargo.toml | 2 +- crates/rover-client/src/blocking/client.rs | 10 ++--- .../src/blocking/studio_client.rs | 13 +++++-- crates/rover-client/tests/client.rs | 27 +++++++++++++ src/command/graph/introspect.rs | 2 +- src/command/subgraph/introspect.rs | 2 +- src/command/supergraph/compose/do_compose.rs | 2 +- src/utils/client.rs | 2 +- 9 files changed, 84 insertions(+), 14 deletions(-) create mode 100644 crates/rover-client/tests/client.rs diff --git a/Cargo.lock b/Cargo.lock index 6ee17d66b..d7e2a112a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "addr2line" version = "0.15.2" @@ -94,6 +96,19 @@ dependencies = [ "tempfile", ] +[[package]] +name = "async-compression" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443ccbb270374a2b1055fc72da40e1f237809cd6bb0e97e66d264cd138473a6" +dependencies = [ + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", +] + [[package]] name = "atty" version = "0.2.14" @@ -360,6 +375,15 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +dependencies = [ + "cfg-if", +] + [[package]] name = "crossbeam" version = "0.8.1" @@ -623,6 +647,18 @@ dependencies = [ "synstructure", ] +[[package]] +name = "flate2" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0" +dependencies = [ + "cfg-if", + "crc32fast", + "libc", + "miniz_oxide", +] + [[package]] name = "float-cmp" version = "0.8.0" @@ -1820,6 +1856,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2296f2fac53979e8ccbc4a1136b25dcefd37be9ed7e4a1f6b05a6029c84ff124" dependencies = [ + "async-compression", "base64", "bytes", "encoding_rs", @@ -1845,6 +1882,7 @@ dependencies = [ "tokio", "tokio-native-tls", "tokio-rustls", + "tokio-util", "url", "wasm-bindgen", "wasm-bindgen-futures", diff --git a/crates/rover-client/Cargo.toml b/crates/rover-client/Cargo.toml index f2b44798f..b3a8371eb 100644 --- a/crates/rover-client/Cargo.toml +++ b/crates/rover-client/Cargo.toml @@ -18,7 +18,7 @@ graphql-parser = "0.3.0" graphql_client = "0.9" http = "0.2" regex = "1.5.4" -reqwest = {version = "0.11", default-features = false, features = ["json", "blocking", "rustls-tls"]} +reqwest = {version = "0.11", default-features = false, features = ["json", "blocking", "rustls-tls", "gzip"]} sdl-encoder = {path = "../sdl-encoder"} serde = "1" serde_json = "1" diff --git a/crates/rover-client/src/blocking/client.rs b/crates/rover-client/src/blocking/client.rs index 0b2f92758..167b7a2bc 100644 --- a/crates/rover-client/src/blocking/client.rs +++ b/crates/rover-client/src/blocking/client.rs @@ -3,7 +3,7 @@ use graphql_client::{Error as GraphQLError, GraphQLQuery, Response as GraphQLRes use reqwest::{ blocking::{Client as ReqwestClient, Response}, header::HeaderMap, - StatusCode, + Error as ReqwestError, StatusCode, }; use std::collections::HashMap; @@ -16,11 +16,11 @@ pub struct GraphQLClient { impl GraphQLClient { /// Construct a new [Client] from a `graphql_endpoint`. /// This client is used for generic GraphQL requests, such as introspection. - pub fn new(graphql_endpoint: &str) -> GraphQLClient { - GraphQLClient { - client: ReqwestClient::new(), + pub fn new(graphql_endpoint: &str) -> Result { + Ok(GraphQLClient { + client: ReqwestClient::builder().gzip(true).build()?, graphql_endpoint: graphql_endpoint.to_string(), - } + }) } /// Client method for making a GraphQL request. diff --git a/crates/rover-client/src/blocking/studio_client.rs b/crates/rover-client/src/blocking/studio_client.rs index 64f237454..22b2d15b1 100644 --- a/crates/rover-client/src/blocking/studio_client.rs +++ b/crates/rover-client/src/blocking/studio_client.rs @@ -2,6 +2,7 @@ use crate::{blocking::GraphQLClient, headers, RoverClientError}; use houston::Credential; use graphql_client::GraphQLQuery; +use reqwest::Error as ReqwestError; /// Represents a client for making GraphQL requests to Apollo Studio. pub struct StudioClient { @@ -13,12 +14,16 @@ pub struct StudioClient { impl StudioClient { /// Construct a new [StudioClient] from an `api_key`, a `uri`, and a `version`. /// For use in Rover, the `uri` is usually going to be to Apollo Studio - pub fn new(credential: Credential, graphql_endpoint: &str, version: &str) -> StudioClient { - StudioClient { + pub fn new( + credential: Credential, + graphql_endpoint: &str, + version: &str, + ) -> Result { + Ok(StudioClient { credential, - client: GraphQLClient::new(graphql_endpoint), + client: GraphQLClient::new(graphql_endpoint)?, version: version.to_string(), - } + }) } /// Client method for making a GraphQL request to Apollo Studio. diff --git a/crates/rover-client/tests/client.rs b/crates/rover-client/tests/client.rs new file mode 100644 index 000000000..5a8486201 --- /dev/null +++ b/crates/rover-client/tests/client.rs @@ -0,0 +1,27 @@ +const STUDIO_PROD_API_ENDPOINT: &str = "https://graphql.api.apollographql.com/api/graphql"; + +#[cfg(test)] +mod tests { + use houston::{Credential, CredentialOrigin}; + use rover_client::blocking::{GraphQLClient, StudioClient}; + + use crate::STUDIO_PROD_API_ENDPOINT; + + #[test] + fn it_can_build_client() { + assert!(GraphQLClient::new(STUDIO_PROD_API_ENDPOINT).is_ok()); + } + + #[test] + fn it_can_build_studio_client() { + assert!(StudioClient::new( + Credential { + api_key: "api:key:here".to_string(), + origin: CredentialOrigin::EnvVar, + }, + "0.1.0", + STUDIO_PROD_API_ENDPOINT + ) + .is_ok()); + } +} diff --git a/src/command/graph/introspect.rs b/src/command/graph/introspect.rs index fa6b4aa03..25e270bef 100644 --- a/src/command/graph/introspect.rs +++ b/src/command/graph/introspect.rs @@ -28,7 +28,7 @@ pub struct Introspect { impl Introspect { pub fn run(&self) -> Result { - let client = GraphQLClient::new(&self.endpoint.to_string()); + let client = GraphQLClient::new(&self.endpoint.to_string())?; // add the flag headers to a hashmap to pass along to rover-client let mut headers = HashMap::new(); diff --git a/src/command/subgraph/introspect.rs b/src/command/subgraph/introspect.rs index 19431b4da..4b69876f0 100644 --- a/src/command/subgraph/introspect.rs +++ b/src/command/subgraph/introspect.rs @@ -33,7 +33,7 @@ pub struct Introspect { impl Introspect { pub fn run(&self) -> Result { - let client = GraphQLClient::new(&self.endpoint.to_string()); + let client = GraphQLClient::new(&self.endpoint.to_string())?; // add the flag headers to a hashmap to pass along to rover-client let mut headers = HashMap::new(); diff --git a/src/command/supergraph/compose/do_compose.rs b/src/command/supergraph/compose/do_compose.rs index fefb69328..781845afb 100644 --- a/src/command/supergraph/compose/do_compose.rs +++ b/src/command/supergraph/compose/do_compose.rs @@ -102,7 +102,7 @@ pub(crate) fn get_subgraph_definitions( SchemaSource::SubgraphIntrospection { subgraph_url } => { // given a federated introspection URL, use subgraph introspect to // obtain SDL and add it to subgraph_definition. - let client = GraphQLClient::new(&subgraph_url.to_string()); + let client = GraphQLClient::new(&subgraph_url.to_string())?; let introspection_response = introspect::run(&client, &HashMap::new())?; let schema = introspection_response.result; diff --git a/src/utils/client.rs b/src/utils/client.rs index 4f010a8ed..e511c747d 100644 --- a/src/utils/client.rs +++ b/src/utils/client.rs @@ -30,6 +30,6 @@ impl StudioClientConfig { pub fn get_client(&self, profile_name: &str) -> Result { let credential = config::Profile::get_credential(profile_name, &self.config)?; - Ok(StudioClient::new(credential, &self.uri, &self.version)) + Ok(StudioClient::new(credential, &self.uri, &self.version)?) } }