Skip to content

Commit 65f14e1

Browse files
authored
Add WebAssembly demo (#953)
1 parent 1a138ce commit 65f14e1

File tree

9 files changed

+151
-9
lines changed

9 files changed

+151
-9
lines changed

.circleci/config.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,11 @@ jobs:
106106
rust_channel: << parameters.rust_channel >>
107107
platform: << parameters.platform >>
108108
- run:
109-
name: Build to wasm target
110-
command: rustup target add wasm32-unknown-unknown && cargo build --package apollo-parser --package apollo-compiler --target wasm32-unknown-unknown
109+
name: Install wasm-pack
110+
command: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
111+
- run:
112+
name: Build wasm demo
113+
command: wasm-pack build --target web examples/validation-wasm-demo
111114

112115
test:
113116
parameters:

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ members = [
55
"crates/apollo-parser",
66
"crates/apollo-compiler",
77
"crates/apollo-smith",
8-
"fuzz",
8+
"fuzz",
9+
"examples/validation-wasm-demo",
910
]

crates/apollo-compiler/Cargo.toml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,6 @@ thiserror = "1.0.31"
2929
triomphe = "0.1.13"
3030
typed-arena = "2.0"
3131

32-
[target.'cfg(target_arch = "wasm32")'.dependencies]
33-
uuid = { version = "1.6", features = ["serde", "v4", "js"] }
34-
3532
[dev-dependencies]
3633
anyhow = "1.0"
3734
criterion = "0.5.1"

crates/apollo-compiler/src/executable/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -794,7 +794,7 @@ impl Field {
794794
}
795795

796796
pub fn with_opt_alias(mut self, alias: Option<Name>) -> Self {
797-
self.alias = alias.map(Into::into);
797+
self.alias = alias;
798798
self
799799
}
800800

crates/apollo-compiler/src/validation/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,7 +1028,7 @@ impl DiagnosticList {
10281028
}
10291029
}
10301030

1031-
/// Use Debug formatting to output with colors: `format!("{diagnostics:?}")`
1031+
/// Use Display formatting to output without colors: `format!("{diagnostics}")`
10321032
impl fmt::Display for DiagnosticList {
10331033
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
10341034
for diagnostic in self.iter() {
@@ -1038,7 +1038,7 @@ impl fmt::Display for DiagnosticList {
10381038
}
10391039
}
10401040

1041-
/// Use Display formatting to output without colors: `format!("{diagnostics}")`
1041+
/// Use Debug formatting to output with colors: `format!("{diagnostics:?}")`
10421042
impl fmt::Debug for DiagnosticList {
10431043
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
10441044
for diagnostic in self.iter() {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "validation-wasm-demo"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[lib]
7+
crate-type = ["cdylib"]
8+
9+
[dependencies]
10+
apollo-compiler.path = "../../crates/apollo-compiler"
11+
# https://docs.rs/getrandom/0.2.15/getrandom/index.html#webassembly-support
12+
getrandom = { version = "0.2", features = ["js"] }
13+
wasm-bindgen = "0.2.100"
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# WebAssembly demo of GraphQL validation
2+
3+
1. [Install wasm-pack](https://rustwasm.github.io/wasm-pack/installer/)
4+
2. Install either [miniserve](https://crates.io/crates/miniserve) with `cargo install miniserve`,
5+
or Python
6+
3. Move to this directory if needed: `cd examples/validation-wasm-demo`
7+
3. Build with `wasm-pack build --target web`
8+
4. Start an HTTP server with `miniserve --index index.html` or `python3 -m http.server`
9+
5. Navigate to [http://127.0.0.1:8080/](http://127.0.0.1:8080/)
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<!doctype html>
2+
<html>
3+
4+
<head>
5+
<meta charset=utf-8>
6+
<title>GraphQL validation in Wasm demo</title>
7+
<style>
8+
html {
9+
margin: 0;
10+
padding: 0;
11+
color: #222;
12+
}
13+
14+
body {
15+
margin: 0 auto;
16+
padding: 1em;
17+
max-width: 120ch;
18+
font-family: sans-serif;
19+
}
20+
21+
h1 {
22+
border-bottom: 1px solid;
23+
}
24+
25+
body>div {
26+
display: flex;
27+
flex-wrap: wrap;
28+
gap: 1em;
29+
}
30+
31+
body>div>div {
32+
flex: 1;
33+
min-width: 40ch;
34+
}
35+
36+
textarea {
37+
width: 100%;
38+
height: 15em;
39+
box-sizing: border-box;
40+
}
41+
</style>
42+
</head>
43+
44+
<body>
45+
<h1>GraphQL validation in Wasm demo</h1>
46+
<div>
47+
<div>
48+
<h2>Schema</h2>
49+
<textarea id=schema>
50+
type Query {
51+
field1: Int64
52+
}
53+
</textarea>
54+
</div>
55+
<div>
56+
<h2>Executable Document</h2>
57+
<textarea id=executable>
58+
{ field2 }
59+
</textarea>
60+
</div>
61+
</div>
62+
<h2>Diagnostics</h2>
63+
<button id=validate>Validate</button>
64+
<pre id=diagnostics></pre>
65+
66+
<script type="module">
67+
import init, { validate } from './pkg/validation_wasm_demo.js';
68+
async function run() {
69+
await init();
70+
document.getElementById("validate").addEventListener("click", function (e) {
71+
let result = validate(
72+
document.getElementById("schema").value,
73+
document.getElementById("executable").value,
74+
);
75+
document.getElementById("diagnostics").textContent = result || "No error!";
76+
});
77+
}
78+
run();
79+
</script>
80+
</body>
81+
82+
</html>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
use wasm_bindgen::prelude::*;
2+
3+
/// Returns diagnostics formatted to a string,
4+
/// or `None` / `null` if the schema and documents are valid together.
5+
///
6+
/// The format is intitially intended for terminal output and contains symbol-based
7+
/// underlyning and arrows that require a monospace font to display properly.
8+
///
9+
/// This interface is just enough for a demo.
10+
/// In a real application you may want something more structured.
11+
#[wasm_bindgen]
12+
pub fn validate(schema_sdl: &str, executable_document: &str) -> Option<String> {
13+
let schema_result = apollo_compiler::Schema::parse_and_validate(schema_sdl, "schema.graphql");
14+
if executable_document.trim().is_empty() {
15+
return schema_result.err().map(|e| e.to_string());
16+
}
17+
let schema = match &schema_result {
18+
Ok(s) => s,
19+
Err(with_errors) => {
20+
apollo_compiler::validation::Valid::assume_valid_ref(&with_errors.partial)
21+
}
22+
};
23+
let executable_result = apollo_compiler::ExecutableDocument::parse_and_validate(
24+
schema,
25+
executable_document,
26+
"executable.graphql",
27+
);
28+
match (schema_result, executable_result) {
29+
(Ok(_), Ok(_)) => None,
30+
(Ok(_), Err(e)) => Some(e.to_string()),
31+
(Err(e), Ok(_)) => Some(e.to_string()),
32+
(Err(mut e1), Err(e2)) => {
33+
e1.errors.merge(e2.errors);
34+
Some(e1.to_string())
35+
}
36+
}
37+
}

0 commit comments

Comments
 (0)