Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/github/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ edition = "2018"
anyhow = "1.0"
graphql_client = { path = "../../graphql_client" }
serde = "^1.0"
reqwest = "^0.9"
reqwest = { version = "^0.10", features = ["json", "blocking"] }
prettytable-rs = "^0.7"
structopt = "^0.3"
dotenv = "^0.13"
Expand Down
4 changes: 2 additions & 2 deletions examples/github/examples/github.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ fn main() -> Result<(), anyhow::Error> {
name: name.to_string(),
});

let client = reqwest::Client::new();
let client = reqwest::blocking::Client::new();

let mut res = client
let res = client
.post("https://api.github.com/graphql")
.bearer_auth(config.github_api_token)
.json(&q)
Expand Down
2 changes: 1 addition & 1 deletion examples/hasura/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ graphql_client = { path = "../../graphql_client" }
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
reqwest = "^0.9.0"
reqwest = { version = "^0.10", features = ["json", "blocking"] }
prettytable-rs = "0.7.0"
dotenv = "0.13.0"
log = "0.4.3"
Expand Down
4 changes: 2 additions & 2 deletions examples/hasura/examples/hasura.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ fn main() -> Result<(), anyhow::Error> {
update_columns: vec![Name, Status, SalesforceUpdatedAt],
});

let client = reqwest::Client::new();
let client = reqwest::blocking::Client::new();

let mut res = client
let res = client
.post("https://localhost:8080/v1/graphql")
.json(&q)
.send()?;
Expand Down
4 changes: 2 additions & 2 deletions examples/web/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ wasm-bindgen = "^0.2"
serde = { version = "1.0.67", features = ["derive"] }
lazy_static = "1.0.1"
js-sys = "0.3.6"
futures = "0.1.25"
wasm-bindgen-futures = "0.3.6"
futures-util = "0.3.8"
wasm-bindgen-futures = "0.4.18"

[dev-dependencies.web-sys]
version = "0.3.6"
Expand Down
26 changes: 10 additions & 16 deletions examples/web/examples/web.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use futures::Future;
use graphql_client::GraphQLQuery;
use lazy_static::*;
use std::cell::RefCell;
Expand All @@ -23,28 +22,23 @@ lazy_static! {
static ref LAST_ENTRY: Mutex<RefCell<Option<String>>> = Mutex::new(RefCell::new(None));
}

fn load_more() -> impl Future<Item = JsValue, Error = JsValue> {
async fn load_more() -> Result<JsValue, JsValue> {
let client = graphql_client::web::Client::new("https://www.graphqlhub.com/graphql");
let variables = puppy_smiles::Variables {
after: LAST_ENTRY
.lock()
.ok()
.and_then(|opt| opt.borrow().to_owned()),
};
let response = client.call(PuppySmiles, variables);

response
.map(|response| {
render_response(response);
JsValue::NULL
})
.map_err(|err| {
log(&format!(
"Could not fetch puppies. graphql_client_web error: {:?}",
err
));
JsValue::NULL
})
let response = client.call(PuppySmiles, variables).await.map_err(|err| {
log(&format!(
"Could not fetch puppies. graphql_client_web error: {:?}",
err
));
JsValue::NULL
})?;
render_response(response);
Ok(JsValue::NULL)
}

fn document() -> web_sys::Document {
Expand Down
12 changes: 2 additions & 10 deletions graphql_client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ graphql_query_derive = { path = "../graphql_query_derive", version = "0.9.0", op
serde_json = "1.0"
serde = { version = "^1.0.78", features = ["derive"] }

[dependencies.futures]
version = "^0.1"
optional = true

[dependencies.js-sys]
version = "^0.3"
optional = true
Expand All @@ -39,22 +35,18 @@ version = "^0.2"
optional = true

[dependencies.wasm-bindgen-futures]
version = "^0.3"
version = "^0.4"
optional = true

[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
reqwest = "^0.9"

[dev-dependencies]
# Note: If we bumpup wasm-bindge-test version, we should change CI setting.
wasm-bindgen-test = "^0.2"
wasm-bindgen-test = "^0.3"

[features]
default = ["graphql_query_derive"]
web = [
"anyhow",
"thiserror",
"futures",
"js-sys",
"log",
"wasm-bindgen",
Expand Down
102 changes: 43 additions & 59 deletions graphql_client/src/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
//! [wasm-bindgen](https://github.com/rustwasm/wasm-bindgen).

use crate::*;
use futures::{Future, IntoFuture};
use log::*;
use std::collections::HashMap;
use thiserror::*;
Expand Down Expand Up @@ -75,71 +74,56 @@ impl Client {
///
// Lint disabled: We can pass by value because it's always an empty struct.
#[allow(clippy::needless_pass_by_value)]
pub fn call<Q: GraphQLQuery + 'static>(
pub async fn call<Q: GraphQLQuery + 'static>(
&self,
_query: Q,
variables: Q::Variables,
) -> impl Future<Item = crate::Response<Q::ResponseData>, Error = ClientError> + 'static {
// this can be removed when we convert to async/await
let endpoint = self.endpoint.clone();
let custom_headers = self.headers.clone();
) -> Result<crate::Response<Q::ResponseData>, ClientError> {
let window = web_sys::window().ok_or_else(|| ClientError::NoWindow)?;
let body =
serde_json::to_string(&Q::build_query(variables)).map_err(|_| ClientError::Body)?;

web_sys::window()
.ok_or_else(|| ClientError::NoWindow)
.into_future()
.and_then(move |window| {
serde_json::to_string(&Q::build_query(variables))
.map_err(|_| ClientError::Body)
.map(move |body| (window, body))
})
.and_then(move |(window, body)| {
let mut request_init = web_sys::RequestInit::new();
request_init
.method("POST")
.body(Some(&JsValue::from_str(&body)));
let mut request_init = web_sys::RequestInit::new();
request_init
.method("POST")
.body(Some(&JsValue::from_str(&body)));

web_sys::Request::new_with_str_and_init(&endpoint, &request_init)
.map_err(|_| ClientError::JsException)
.map(|request| (window, request))
// "Request constructor threw");
})
.and_then(move |(window, request)| {
let headers = request.headers();
headers
.set("Content-Type", "application/json")
.map_err(|_| ClientError::RequestError)?;
headers
.set("Accept", "application/json")
.map_err(|_| ClientError::RequestError)?;
let request = web_sys::Request::new_with_str_and_init(&self.endpoint, &request_init)
.map_err(|_| ClientError::JsException)?;

for (header_name, header_value) in custom_headers.iter() {
headers
.set(header_name, header_value)
.map_err(|_| ClientError::RequestError)?;
}
let headers = request.headers();
headers
.set("Content-Type", "application/json")
.map_err(|_| ClientError::RequestError)?;
headers
.set("Accept", "application/json")
.map_err(|_| ClientError::RequestError)?;
for (header_name, header_value) in self.headers.iter() {
headers
.set(header_name, header_value)
.map_err(|_| ClientError::RequestError)?;
}

let res = JsFuture::from(window.fetch_with_request(&request))
.await
.map_err(|err| ClientError::Network(js_sys::Error::from(err).message().into()))?;
debug!("response: {:?}", res);
let cast_response = res
.dyn_into::<web_sys::Response>()
.map_err(|_| ClientError::Cast)?;

let text_promise = cast_response
.text()
.map_err(|_| ClientError::ResponseText)?;
let text = JsFuture::from(text_promise)
.await
.map_err(|_| ClientError::ResponseText)?;

Ok((window, request))
})
.and_then(move |(window, request)| {
JsFuture::from(window.fetch_with_request(&request))
.map_err(|err| ClientError::Network(js_sys::Error::from(err).message().into()))
})
.and_then(move |res| {
debug!("response: {:?}", res);
res.dyn_into::<web_sys::Response>()
.map_err(|_| ClientError::Cast)
})
.and_then(move |cast_response| {
cast_response.text().map_err(|_| ClientError::ResponseText)
})
.and_then(move |text_promise| {
JsFuture::from(text_promise).map_err(|_| ClientError::ResponseText)
})
.and_then(|text| {
let response_text = text.as_string().unwrap_or_default();
debug!("response text as string: {:?}", response_text);
serde_json::from_str(&response_text).map_err(|_| ClientError::ResponseShape)
})
let response_text = text.as_string().unwrap_or_default();
debug!("response text as string: {:?}", response_text);
let response_data =
serde_json::from_str(&response_text).map_err(|_| ClientError::ResponseShape)?;
Ok(response_data)
}
}

Expand Down
2 changes: 1 addition & 1 deletion graphql_client/tests/Germany.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ query Germany {
}
}

query Country($countryCode: String!) {
query Country($countryCode: ID!) {
country(code: $countryCode) {
name
continent {
Expand Down
98 changes: 43 additions & 55 deletions graphql_client/tests/web.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
#![cfg(target_arch = "wasm32")]

use futures::Future;
use graphql_client::{web::Client, GraphQLQuery};
use wasm_bindgen::JsValue;
use wasm_bindgen_test::wasm_bindgen_test_configure;
use wasm_bindgen_test::*;

wasm_bindgen_test_configure!(run_in_browser);
Expand All @@ -18,30 +15,27 @@ fn build_client() {
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "tests/countries_schema.json",
query_path = "tests/Germany.graphql"
query_path = "tests/Germany.graphql",
response_derives = "Debug"
)]
struct Germany;

#[wasm_bindgen_test(async)]
fn test_germany() -> impl Future<Item = (), Error = JsValue> {
Client::new("https://countries.trevorblades.com/")
#[wasm_bindgen_test]
async fn test_germany() {
let response = Client::new("https://countries.trevorblades.com/")
.call(Germany, germany::Variables)
.map(|response| {
let continent_name = response
.data
.expect("response data is not null")
.country
.expect("country is not null")
.continent
.expect("continent is not null")
.name
.expect("germany is on a continent");

assert_eq!(continent_name, "Europe");
})
.map_err(|err| {
panic!("{:?}", err);
})
.await
.expect("successful response");
let continent_name = response
.data
.expect("response data is not null")
.country
.expect("country is not null")
.continent
.expect("continent is not null")
.name
.expect("germany is on a continent");
assert_eq!(continent_name, "Europe");
}

#[derive(GraphQLQuery)]
Expand All @@ -51,50 +45,44 @@ fn test_germany() -> impl Future<Item = (), Error = JsValue> {
)]
struct Country;

#[wasm_bindgen_test(async)]
fn test_country() -> impl Future<Item = (), Error = JsValue> {
Client::new("https://countries.trevorblades.com/")
#[wasm_bindgen_test]
async fn test_country() {
let response = Client::new("https://countries.trevorblades.com/")
.call(
Country,
country::Variables {
country_code: "CN".to_owned(),
},
)
.map(|response| {
let continent_name = response
.data
.expect("response data is not null")
.country
.expect("country is not null")
.continent
.expect("continent is not null")
.name
.expect("country is on a continent");

assert_eq!(continent_name, "Asia");
})
.map_err(|err| {
panic!("{:?}", err);
})
.await
.expect("successful response");
let continent_name = response
.data
.expect("response data is not null")
.country
.expect("country is not null")
.continent
.expect("continent is not null")
.name
.expect("country is on a continent");
assert_eq!(continent_name, "Asia");
}

#[wasm_bindgen_test(async)]
fn test_bad_url() -> impl Future<Item = (), Error = JsValue> {
Client::new("https://example.com/non-existent/graphql/endpoint")
#[wasm_bindgen_test]
async fn test_bad_url() {
let result = Client::new("https://example.com/non-existent/graphql/endpoint")
.call(
Country,
country::Variables {
country_code: "CN".to_owned(),
},
)
.map(|_response| panic!("The API endpoint does not exist, this should not be called."))
.map_err(|err| {
assert_eq!(
err,
graphql_client::web::ClientError::Network(
"NetworkError when attempting to fetch resource.".into()
)
);
})
.then(|_| Ok(()))
.await;
match result {
Ok(_response) => panic!("The API endpoint does not exist, this should not be called."),
Err(graphql_client::web::ClientError::Network(msg)) => {
assert_eq!(msg, "NetworkError when attempting to fetch resource.")
}
Err(err) => panic!("unexpected error: {}", err),
}
}
Loading