Skip to content

Commit c39a41f

Browse files
committed
Port the wasm example to graphql_client_web and web_sys
1 parent c2128f9 commit c39a41f

File tree

6 files changed

+120
-130
lines changed

6 files changed

+120
-130
lines changed

graphql_client/examples/call_from_js/Cargo.toml

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
name = "call_from_js"
33
version = "0.1.0"
44
authors = ["Tom Houlé <[email protected]>"]
5+
edition = "2018"
56

67
[profile.release]
78
lto = "thin"
@@ -10,12 +11,28 @@ lto = "thin"
1011
crate-type = ["cdylib"]
1112

1213
[dependencies]
13-
graphql_client = { path = "../..", version = "0.4.0" }
14+
graphql_client_web = { path = "../../../graphql_client_web" }
1415
wasm-bindgen = "0.2.12"
1516
serde = "1.0.67"
1617
serde_derive = "1.0.67"
1718
serde_json = "1.0.22"
1819
lazy_static = "1.0.1"
20+
js-sys = "0.3.6"
21+
futures = "0.1.25"
22+
wasm-bindgen-futures = "0.3.6"
23+
24+
[dependencies.web-sys]
25+
version = "0.3.6"
26+
features = [
27+
"console",
28+
"Document",
29+
"Element",
30+
"EventTarget",
31+
"Node",
32+
"HtmlBodyElement",
33+
"HtmlDocument",
34+
"HtmlElement",
35+
]
1936

2037
[workspace]
2138
members = ["."]

graphql_client/examples/call_from_js/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# call from JS example
22

3-
This is a demo of the library used for webassembly.
3+
This is a demo of the library compiled to webassembly for use in a browser.
44

55
## Build
66

graphql_client/examples/call_from_js/convenient_fetch.js

Lines changed: 0 additions & 14 deletions
This file was deleted.

graphql_client/examples/call_from_js/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
"serve": "webpack-dev-server"
44
},
55
"devDependencies": {
6-
"webpack": "^4.0.1",
7-
"webpack-cli": "^2.0.10",
8-
"webpack-dev-server": "^3.1.0"
6+
"webpack": "^4.28.3",
7+
"webpack-cli": "^3.1.2",
8+
"webpack-dev-server": "^3.1.14"
99
}
1010
}

graphql_client/examples/call_from_js/src/lib.rs

Lines changed: 97 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,157 +1,144 @@
1-
#![feature(use_extern_macros)]
2-
3-
#[macro_use]
4-
extern crate graphql_client;
5-
extern crate serde;
6-
#[macro_use]
7-
extern crate serde_derive;
8-
extern crate serde_json;
9-
#[macro_use]
10-
extern crate lazy_static;
11-
1+
use futures::Future;
2+
use lazy_static::*;
123
use std::cell::RefCell;
134
use std::sync::Mutex;
145

15-
extern crate wasm_bindgen;
166
use wasm_bindgen::prelude::*;
7+
use wasm_bindgen_futures::future_to_promise;
178

18-
use graphql_client::*;
9+
use graphql_client_web::*;
1910

2011
#[derive(GraphQLQuery)]
2112
#[graphql(
2213
schema_path = "schema.json",
23-
query_path = "src/puppy_smiles.graphql"
14+
query_path = "src/puppy_smiles.graphql",
15+
response_derives = "Debug"
2416
)]
2517
struct PuppySmiles;
2618

27-
#[wasm_bindgen]
28-
extern "C" {
29-
#[wasm_bindgen(js_namespace = console)]
30-
fn log(s: &str);
31-
32-
type HTMLDocument;
33-
static document: HTMLDocument;
34-
#[wasm_bindgen(method)]
35-
fn createElement(this: &HTMLDocument, tagName: &str) -> Element;
36-
#[wasm_bindgen(method, getter)]
37-
fn body(this: &HTMLDocument) -> Element;
38-
39-
type Element;
40-
#[wasm_bindgen(method, setter = innerHTML)]
41-
fn set_inner_html(this: &Element, html: &str);
42-
#[wasm_bindgen(method, js_name = appendChild)]
43-
fn append_child(this: &Element, other: Element);
44-
#[wasm_bindgen(method, js_name = addEventListener)]
45-
fn add_event_listener(this: &Element, event: &str, cb: &Closure<Fn()>);
46-
}
47-
48-
#[wasm_bindgen(module = "./convenient_fetch")]
49-
extern "C" {
50-
fn convenient_post(
51-
req: &str,
52-
body: String,
53-
on_complete: &Closure<Fn(String)>,
54-
on_error: &Closure<Fn()>,
55-
);
19+
fn log(s: &str) {
20+
web_sys::console::log_1(&JsValue::from_str(s))
5621
}
5722

5823
lazy_static! {
5924
static ref LAST_ENTRY: Mutex<RefCell<Option<String>>> = Mutex::new(RefCell::new(None));
6025
}
6126

62-
fn load_more() {
63-
let cb = cb();
64-
let on_error = on_error();
65-
convenient_post(
66-
"https://www.graphqlhub.com/graphql",
67-
serde_json::to_string(&PuppySmiles::build_query(puppy_smiles::Variables {
68-
after: LAST_ENTRY
69-
.lock()
70-
.ok()
71-
.and_then(|opt| opt.borrow().to_owned()),
72-
})).unwrap(),
73-
&cb,
74-
&on_error,
75-
);
27+
fn load_more() -> impl Future<Item = JsValue, Error = JsValue> {
28+
let client = graphql_client_web::Client::new("https://www.graphqlhub.com/graphql");
29+
let variables = puppy_smiles::Variables {
30+
after: LAST_ENTRY
31+
.lock()
32+
.ok()
33+
.and_then(|opt| opt.borrow().to_owned()),
34+
};
35+
let response = client.call(PuppySmiles, variables);
36+
37+
response
38+
.map(|response| {
39+
render_response(response);
40+
JsValue::NULL
41+
})
42+
.map_err(|err| {
43+
log(&format!(
44+
"Could not fetch puppies. graphql_client_web error: {:?}",
45+
err
46+
));
47+
JsValue::NULL
48+
})
49+
}
7650

77-
cb.forget();
78-
on_error.forget();
51+
fn document() -> web_sys::Document {
52+
web_sys::window()
53+
.expect("no window")
54+
.document()
55+
.expect("no document")
7956
}
8057

8158
fn add_load_more_button() {
82-
let btn = document.createElement("button");
59+
let btn = document()
60+
.create_element("button")
61+
.expect("could not create button");
8362
btn.set_inner_html("I WANT MORE PUPPIES");
84-
let on_click = Closure::new(move || load_more());
85-
btn.add_event_listener("click", &on_click);
63+
let on_click = Closure::wrap(
64+
Box::new(move || future_to_promise(load_more())) as Box<FnMut() -> js_sys::Promise>
65+
);
66+
btn.add_event_listener_with_callback(
67+
"click",
68+
js_sys::Function::try_from(&on_click.as_ref()).expect("on click is not a Function"),
69+
)
70+
.expect("could not add event listener to load more button");
8671

87-
let doc = document.body();
88-
doc.append_child(btn);
72+
let doc = document().body().expect("no body");
73+
doc.append_child(&btn).expect("could not append button");
8974

9075
on_click.forget();
9176
}
9277

93-
fn cb() -> Closure<Fn(String)> {
78+
fn render_response(response: graphql_client_web::Response<puppy_smiles::ResponseData>) {
9479
use std::fmt::Write;
9580

96-
Closure::new(move |s: String| {
97-
log(&format!("response body\n\n{}", s));
98-
99-
let parent = document.body();
100-
101-
let json: Response<puppy_smiles::ResponseData> =
102-
serde_json::from_str(&s).expect("failed to deserialize");
103-
let response = document.createElement("div");
104-
let mut inner_html = String::new();
105-
let listings = json
106-
.data
107-
.expect("response data")
108-
.reddit
109-
.expect("reddit")
110-
.subreddit
111-
.expect("puppy smiles subreddit")
112-
.new_listings;
113-
114-
let new_cursor: Option<String> = listings[listings.len() - 1]
115-
.as_ref()
116-
.map(|puppy| puppy.fullname_id.clone())
117-
.to_owned();
118-
LAST_ENTRY.lock().unwrap().replace(new_cursor);
119-
120-
for puppy in &listings {
121-
if let Some(puppy) = puppy {
122-
write!(
123-
inner_html,
124-
r#"
81+
log(&format!("response body\n\n{:?}", response));
82+
83+
let parent = document().body().expect("no body");
84+
85+
let json: graphql_client_web::Response<puppy_smiles::ResponseData> = response;
86+
let response = document()
87+
.create_element("div")
88+
.expect("could not create div");
89+
let mut inner_html = String::new();
90+
let listings = json
91+
.data
92+
.expect("response data")
93+
.reddit
94+
.expect("reddit")
95+
.subreddit
96+
.expect("puppy smiles subreddit")
97+
.new_listings;
98+
99+
let new_cursor: Option<String> = listings[listings.len() - 1]
100+
.as_ref()
101+
.map(|puppy| puppy.fullname_id.clone())
102+
.to_owned();
103+
LAST_ENTRY.lock().unwrap().replace(new_cursor);
104+
105+
for puppy in &listings {
106+
if let Some(puppy) = puppy {
107+
write!(
108+
inner_html,
109+
r#"
125110
<div class="card" style="width: 26rem;">
126111
<img class="img-thumbnail card-img-top" alt="{}" src="{}" />
127112
<div class="card-body">
128113
<h5 class="card-title">{}</h5>
129114
</div>
130115
</div>
131116
"#,
132-
puppy.title, puppy.url, puppy.title
133-
).expect("write to string");
134-
}
117+
puppy.title, puppy.url, puppy.title
118+
)
119+
.expect("write to string");
135120
}
136-
response.set_inner_html(&format!(
137-
"<h2>response:</h2><div class=\"container\"><div class=\"row\">{}</div></div>",
138-
inner_html
139-
));
140-
parent.append_child(response);
141-
})
142-
}
143-
144-
fn on_error() -> Closure<Fn()> {
145-
Closure::new(|| log("sad :("))
121+
}
122+
response.set_inner_html(&format!(
123+
"<h2>response:</h2><div class=\"container\"><div class=\"row\">{}</div></div>",
124+
inner_html
125+
));
126+
parent
127+
.append_child(&response)
128+
.expect("could not append response");
146129
}
147130

148131
#[wasm_bindgen]
149132
pub fn run() {
150133
log("Hello there");
151-
let message_area = document.createElement("div");
134+
let message_area = document()
135+
.create_element("div")
136+
.expect("could not create div");
152137
message_area.set_inner_html("<p>good morning</p>");
153-
let parent = document.body();
154-
parent.append_child(message_area);
138+
let parent = document().body().unwrap();
139+
parent
140+
.append_child(&message_area)
141+
.expect("could not append message area");
155142

156143
load_more();
157144
add_load_more_button();

graphql_client_web/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
use failure::*;
99
use futures::{Future, IntoFuture};
10-
pub use graphql_client::{self, GraphQLQuery};
10+
pub use graphql_client::{self, GraphQLQuery, Response};
1111
use log::*;
1212
use std::collections::HashMap;
1313
use wasm_bindgen::{JsCast, JsValue};

0 commit comments

Comments
 (0)