graph_weaver 0.5.1 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +432 -0
- data/Gemfile.lock +19 -19
- data/README.md +75 -54
- data/docs/cassettes.md +6 -1
- data/docs/editors.md +3 -1
- data/docs/errors.md +73 -16
- data/docs/federation.md +201 -151
- data/docs/generated_modules.md +222 -165
- data/docs/getting_started.md +106 -82
- data/docs/logging.md +34 -4
- data/docs/real_world.md +4 -4
- data/docs/scalars.md +206 -46
- data/docs/testing.md +191 -151
- data/docs/transports.md +47 -19
- data/docs/upgrading.md +210 -11
- data/lib/generators/graph_weaver/install_generator.rb +16 -1
- data/lib/graph_weaver/client.rb +46 -13
- data/lib/graph_weaver/codegen/aliases.rb +5 -4
- data/lib/graph_weaver/codegen/emit.rb +96 -39
- data/lib/graph_weaver/codegen/enum_type.rb +3 -0
- data/lib/graph_weaver/codegen/nodes.rb +42 -21
- data/lib/graph_weaver/codegen/scalar_type.rb +167 -98
- data/lib/graph_weaver/codegen/type_helpers.rb +1 -0
- data/lib/graph_weaver/codegen.rb +279 -84
- data/lib/graph_weaver/coerce.rb +113 -0
- data/lib/graph_weaver/errors.rb +30 -7
- data/lib/graph_weaver/federation.rb +6 -5
- data/lib/graph_weaver/hints.rb +76 -2
- data/lib/graph_weaver/in_process.rb +11 -8
- data/lib/graph_weaver/inflect.rb +2 -0
- data/lib/graph_weaver/input_struct.rb +115 -12
- data/lib/graph_weaver/internal/overrides.rb +101 -0
- data/lib/graph_weaver/internal/planner.rb +868 -0
- data/lib/graph_weaver/internal/schemas.rb +50 -0
- data/lib/graph_weaver/internal/selection.rb +127 -0
- data/lib/graph_weaver/{testing → internal}/subgraphs.rb +39 -41
- data/lib/graph_weaver/internal/values.rb +184 -0
- data/lib/graph_weaver/internal.rb +206 -0
- data/lib/graph_weaver/logging.rb +108 -20
- data/lib/graph_weaver/parsing.rb +5 -4
- data/lib/graph_weaver/query_module.rb +2 -0
- data/lib/graph_weaver/railtie.rb +113 -14
- data/lib/graph_weaver/representation.rb +30 -2
- data/lib/graph_weaver/response.rb +15 -0
- data/lib/graph_weaver/retry.rb +54 -22
- data/lib/graph_weaver/rspec.rb +50 -11
- data/lib/graph_weaver/schema_diff.rb +293 -0
- data/lib/graph_weaver/schema_loader.rb +96 -29
- data/lib/graph_weaver/tasks.rb +78 -29
- data/lib/graph_weaver/testing/cassette.rb +49 -65
- data/lib/graph_weaver/testing/coverage.rb +5 -4
- data/lib/graph_weaver/testing/failure.rb +10 -6
- data/lib/graph_weaver/testing/fake_client.rb +253 -60
- data/lib/graph_weaver/testing/fake_subgraph.rb +19 -8
- data/lib/graph_weaver/testing/router.rb +94 -808
- data/lib/graph_weaver/testing.rb +35 -84
- data/lib/graph_weaver/transport/faraday.rb +1 -1
- data/lib/graph_weaver/transport/http.rb +29 -12
- data/lib/graph_weaver/transport.rb +11 -34
- data/lib/graph_weaver/version.rb +1 -1
- data/lib/graph_weaver.rb +203 -119
- metadata +10 -5
- data/lib/graph_weaver/schemas.rb +0 -48
- data/lib/graph_weaver/selection.rb +0 -120
- data/lib/graph_weaver/testing/values.rb +0 -98
data/docs/getting_started.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Getting started: the production path (Rails)
|
|
2
2
|
|
|
3
|
-
The setup that ships: queries live as `.graphql` files, generation
|
|
4
|
-
`# typed: strict` Ruby you check in, and CI fails when anything drifts.
|
|
5
|
-
|
|
3
|
+
The setup that ships, end to end: queries live as `.graphql` files, generation
|
|
4
|
+
writes `# typed: strict` Ruby you check in, and CI fails when anything drifts.
|
|
5
|
+
Follow it once when you add the gem to an app. (Exploring an API from a console
|
|
6
6
|
instead? Start with [dynamic mode](real_world.md) — no build step.)
|
|
7
7
|
|
|
8
8
|
Rails is assumed below; the [non-Rails note](#not-rails) at the bottom
|
|
@@ -24,6 +24,7 @@ rails g graph_weaver:install https://api.example.com/graphql
|
|
|
24
24
|
```
|
|
25
25
|
create config/initializers/graph_weaver.rb
|
|
26
26
|
create app/graphql/queries/.keep
|
|
27
|
+
create app/graphql/fragments/.keep
|
|
27
28
|
create app/graphql/generated/.keep
|
|
28
29
|
create graphql.config.yml
|
|
29
30
|
introspect app/graphql/schema.json from https://api.example.com/graphql
|
|
@@ -57,7 +58,7 @@ What it wrote:
|
|
|
57
58
|
into generated source, so they have to run first:
|
|
58
59
|
|
|
59
60
|
```ruby
|
|
60
|
-
GraphWeaver.register_scalar("
|
|
61
|
+
GraphWeaver.register_scalar("Money", Money) # a scalar the registry can't know
|
|
61
62
|
```
|
|
62
63
|
|
|
63
64
|
A registration that names one of your own constants — a `T::Enum` for
|
|
@@ -84,13 +85,15 @@ What it wrote:
|
|
|
84
85
|
RubyMine schema autocomplete, hover docs, and validation as you type in
|
|
85
86
|
`.graphql` files — no JS project, no `npm install`. Details and the honest
|
|
86
87
|
limits in [editors](editors.md).
|
|
87
|
-
- **`app/graphql/queries/`, `app/graphql/generated/`.**
|
|
88
|
-
queries and where generation
|
|
88
|
+
- **`app/graphql/queries/`, `app/graphql/fragments/`, `app/graphql/generated/`.**
|
|
89
|
+
Where you write queries, where shared fragments live, and where generation
|
|
90
|
+
writes Ruby.
|
|
89
91
|
|
|
90
92
|
Rake needs no wiring either: in Rails the `graph_weaver:*` tasks register
|
|
91
93
|
themselves (a Railtie) and depend on `:environment`, so your initializer —
|
|
92
|
-
and its registrations — runs first. The generated modules load at boot
|
|
93
|
-
|
|
94
|
+
and its registrations — runs first. The generated modules load at boot from
|
|
95
|
+
a `to_prepare` block, so a helper or enum you registered in one is already
|
|
96
|
+
in place when the file that names it loads.
|
|
94
97
|
|
|
95
98
|
### Your app's own schema, in-process
|
|
96
99
|
|
|
@@ -122,11 +125,16 @@ client = GraphWeaver.new(MyApp::Schema, context: { current_user: })
|
|
|
122
125
|
PetQuery.execute!(client:, id: "1").pet.owner # => the context's user
|
|
123
126
|
```
|
|
124
127
|
|
|
128
|
+
Each query gets its own copy of that hash, so a resolver writing
|
|
129
|
+
`context[:loader] =` can't hand what it wrote to the next request — which
|
|
130
|
+
matters because one in-process client is normally the whole app's.
|
|
131
|
+
|
|
125
132
|
**Keep the dump in step with the schema.** Codegen reads the committed
|
|
126
133
|
dump at `GraphWeaver.schema_path`, never the live class — that's what
|
|
127
134
|
makes `rake graph_weaver:verify` a deterministic CI check. The generator
|
|
128
135
|
writes the first dump; after that it's an artifact derived from code in
|
|
129
|
-
your own repo, so rebuild it with graphql-ruby's own rake task
|
|
136
|
+
your own repo, so rebuild it with graphql-ruby's own rake task, ahead of
|
|
137
|
+
`verify` in CI:
|
|
130
138
|
|
|
131
139
|
```ruby
|
|
132
140
|
# lib/tasks/graphql.rake
|
|
@@ -140,13 +148,16 @@ rake graphql:schema:json # rewrites app/graphql/schema.json
|
|
|
140
148
|
rake graph_weaver:generate
|
|
141
149
|
```
|
|
142
150
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
151
|
+
A stale dump makes `verify` fail on a query that is fine. `queries:check` is
|
|
152
|
+
unaffected: running in-process it validates against the live class, not the
|
|
153
|
+
dump. (`schema:diff` and `:refresh` are for servers you *don't* own; a dump
|
|
154
|
+
taken from a schema class records no url, and they say so.)
|
|
155
|
+
|
|
156
|
+
**Scaffolding the app too?** On a `rails new --skip-active-record`,
|
|
157
|
+
`rails g graphql:install` writes `config.active_record.query_log_tags` lines
|
|
158
|
+
into `config/application.rb` that an app without ActiveRecord can't boot
|
|
159
|
+
with — a graphql-ruby bug. Run it as
|
|
160
|
+
`rails g graphql:install --skip-query-logs`, or delete the lines it wrote.
|
|
150
161
|
|
|
151
162
|
### A schema dump you already have
|
|
152
163
|
|
|
@@ -174,19 +185,28 @@ query($id: ID!) {
|
|
|
174
185
|
rake graph_weaver:generate # writes app/graphql/generated/person_query.rb
|
|
175
186
|
```
|
|
176
187
|
|
|
177
|
-
Commit the schema dump and the generated files. Generated code is
|
|
178
|
-
reviewed like any other code — and never edited by hand.
|
|
179
|
-
|
|
180
188
|
```ruby
|
|
181
189
|
PersonQuery.execute!(id: "1").person&.name # typed, via GraphWeaver.client
|
|
182
190
|
```
|
|
183
191
|
|
|
184
|
-
|
|
192
|
+
Commit the schema dump and the generated files. Generated code is reviewed like
|
|
193
|
+
any other code — and never edited by hand. The module name comes from the file
|
|
194
|
+
name; the full set of naming rules is in
|
|
195
|
+
[generated modules](generated_modules.md#naming).
|
|
185
196
|
|
|
186
197
|
`graphql.config.yml` is already there, so VS Code and RubyMine validate the
|
|
187
198
|
`.graphql` files as you type, with schema autocomplete and hover docs — see
|
|
188
199
|
[editors](editors.md).
|
|
189
200
|
|
|
201
|
+
**In development you don't type that command again.** While the server is
|
|
202
|
+
running, a `.graphql` edit — or a refreshed schema dump — regenerates before
|
|
203
|
+
the next request, the way a route or a locale change takes effect. A query that
|
|
204
|
+
doesn't compile is logged with its file and position while the modules already
|
|
205
|
+
loaded keep serving, so a file saved mid-edit doesn't take the server down.
|
|
206
|
+
Development only, and `config.graph_weaver.watch = false` turns it off. The
|
|
207
|
+
generated files are still what ships: commit them, and keep `rake
|
|
208
|
+
graph_weaver:verify` in CI.
|
|
209
|
+
|
|
190
210
|
### Shared fragments
|
|
191
211
|
|
|
192
212
|
Define reusable fragments once and spread them from any query:
|
|
@@ -205,29 +225,10 @@ Fragment files hold only fragments (no operations), and names are unique across
|
|
|
205
225
|
them. Point elsewhere with `GraphWeaver.fragments_paths` (an appendable list,
|
|
206
226
|
default `app/graphql/fragments`).
|
|
207
227
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
it aliases the same type — so a `union` selected across many queries becomes one
|
|
213
|
-
Ruby type family, and you write one exhaustive `case … when … T.absurd` that
|
|
214
|
-
works everywhere:
|
|
215
|
-
|
|
216
|
-
```graphql
|
|
217
|
-
# app/graphql/fragments/feed_item.graphql
|
|
218
|
-
fragment FeedItemFields on FeedItem {
|
|
219
|
-
__typename
|
|
220
|
-
... on Post { title }
|
|
221
|
-
... on Photo { url }
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
# any query
|
|
225
|
-
query { feed { ...FeedItemFields } } # feed : T::Array[FeedItemFields::Type]
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
There's no flag: hoisting triggers when the union field's selection is exactly
|
|
229
|
-
that one spread. Mix in other fields, or shadow the fragment with a query-local
|
|
230
|
-
one of the same name, and the union stays inlined in that query — see
|
|
228
|
+
One payoff worth knowing about: when a shared fragment *is* the whole selection
|
|
229
|
+
on a union field, its type is hoisted once into `GraphQLTypes` and every query
|
|
230
|
+
that spreads it gets the same Ruby type — so one exhaustive `case … T.absurd`
|
|
231
|
+
works everywhere. See
|
|
231
232
|
[abstract types](generated_modules.md#abstract-types).
|
|
232
233
|
|
|
233
234
|
## 4. Test against fakes
|
|
@@ -241,47 +242,74 @@ require "graph_weaver/rspec"
|
|
|
241
242
|
it "renders the empty state", graphql: :fake do … end # or tag the describe
|
|
242
243
|
```
|
|
243
244
|
|
|
245
|
+
The tag installs a seeded, schema-correct `FakeClient` for that example — no
|
|
246
|
+
server, no stubs, and `rspec --seed 1234` reproduces the fake data along with
|
|
247
|
+
test order. The schema it fabricates from is derived (the committed dump, or
|
|
248
|
+
your client's), so there's nothing to configure. Tag `graphql: :in_process`
|
|
249
|
+
instead and the same example runs against your real resolvers. Pinning values,
|
|
250
|
+
simulating failures, and the federated `graphql: :router` are in
|
|
251
|
+
[testing](testing.md).
|
|
252
|
+
|
|
244
253
|
A fresh `rails g rspec:install` leaves the `spec/support` glob commented
|
|
245
254
|
out in `spec/rails_helper.rb`, so uncomment it — or put the require in
|
|
246
255
|
`rails_helper.rb` itself. Nothing warns you that a support file went
|
|
247
256
|
unread.
|
|
248
257
|
|
|
249
|
-
The tag installs a seeded, schema-correct `FakeClient` for that example —
|
|
250
|
-
no server, no stubs, and `rspec --seed 1234` reproduces the fake data along
|
|
251
|
-
with test order. The schema it fabricates from is derived (the committed
|
|
252
|
-
dump, or your client's), so there's nothing to configure. Tag
|
|
253
|
-
`graphql: :in_process` instead and the same example runs against your real
|
|
254
|
-
resolvers; pin values with `overrides:`, simulate failures with `Failure.*`
|
|
255
|
-
— see [testing](testing.md).
|
|
256
|
-
|
|
257
258
|
## 5. Verify in CI
|
|
258
259
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
260
|
+
Four questions, four tasks — the last only on a federated graph:
|
|
261
|
+
|
|
262
|
+
| ask | task | needs network |
|
|
263
|
+
|---|---|---|
|
|
264
|
+
| is the checked-in Ruby fresh? | `rake graph_weaver:verify` | no |
|
|
265
|
+
| has the server's schema drifted from the dump? | `rake graph_weaver:schema:diff` | yes |
|
|
266
|
+
| did that drift break any of my queries? | `rake graph_weaver:queries:check` | yes |
|
|
267
|
+
| did a subgraph change without a recompose? | `rake graph_weaver:federation:diff` | no |
|
|
268
|
+
|
|
269
|
+
`verify` compares the committed generated files against what the current
|
|
270
|
+
schema + queries + registrations would produce, so it belongs in every CI
|
|
271
|
+
build. `schema:diff` needs a dump with a recorded source url (introspected
|
|
272
|
+
dumps have one) and `GRAPHWEAVER_AUTH` for private APIs — run it on a
|
|
273
|
+
schedule and repair with `rake graph_weaver:schema:refresh`.
|
|
274
|
+
`federation:diff` needs no network either, so it goes in the same PR run;
|
|
275
|
+
see [federation](federation.md#has-the-supergraph-been-recomposed).
|
|
276
|
+
|
|
277
|
+
`schema:diff` names what moved, breaking changes first — breaking meaning
|
|
278
|
+
a query written against your dump stops validating, or stops casting:
|
|
279
|
+
|
|
263
280
|
```
|
|
281
|
+
app/graphql/schema.json vs https://api.example.com/graphql: 8 changes, 5 breaking
|
|
282
|
+
|
|
283
|
+
breaking:
|
|
284
|
+
AdoptionInput.nickname String -> String!
|
|
285
|
+
Person.email removed
|
|
286
|
+
Person.pets [Pet!]! -> [Pet!]
|
|
287
|
+
Query.person(includeArchived:) argument added: Boolean! — required
|
|
288
|
+
Species.CAT enum value removed
|
|
264
289
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
[federation](federation.md#has-the-supergraph-been-recomposed).
|
|
290
|
+
other:
|
|
291
|
+
Person.birthday deprecated: use bornOn
|
|
292
|
+
Pet.nickname added: String
|
|
293
|
+
Species.BIRD enum value added
|
|
270
294
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
every CI build.
|
|
295
|
+
app/graphql/schema.json is stale — the server's schema has drifted (rake graph_weaver:schema:refresh)
|
|
296
|
+
```
|
|
274
297
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
298
|
+
Nullability is judged from your side, which is why the two above point
|
|
299
|
+
opposite ways: `Person.pets` losing its `!` hands a generated struct the
|
|
300
|
+
nil it declared it wouldn't get, while `AdoptionInput.nickname` gaining
|
|
301
|
+
one rejects a query that omits it. Any drift exits non-zero — whether a
|
|
302
|
+
change matters is yours to judge.
|
|
279
303
|
|
|
280
|
-
`
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
304
|
+
`GraphWeaver::SchemaLoader.diff(path)` is the same summary as an object —
|
|
305
|
+
`#breaking`, `#compatible`, `#to_h`, and `#empty?` for the plain "has it
|
|
306
|
+
drifted" question.
|
|
307
|
+
|
|
308
|
+
`queries:check` answers the question that actually matters when the schema
|
|
309
|
+
*has* moved: **which of your queries no longer validate, and why.** It
|
|
310
|
+
re-introspects the recorded url (without rewriting the dump) and validates
|
|
311
|
+
every `.graphql` file against the schema as it is right now, naming each
|
|
312
|
+
error's line and column, and exits non-zero:
|
|
285
313
|
|
|
286
314
|
```
|
|
287
315
|
app/graphql/queries/person.graphql
|
|
@@ -290,9 +318,6 @@ app/graphql/queries/person.graphql
|
|
|
290
318
|
1 invalid query
|
|
291
319
|
```
|
|
292
320
|
|
|
293
|
-
It exits non-zero when anything fails, so it drops straight into CI or a
|
|
294
|
-
scheduled job.
|
|
295
|
-
|
|
296
321
|
The Ruby behind it returns the same thing as data, so you can wire it into
|
|
297
322
|
whatever you already have (a spec, a Slack ping, an issue):
|
|
298
323
|
|
|
@@ -303,18 +328,17 @@ GraphWeaver.check_queries
|
|
|
303
328
|
# "line" => 4, "column" => 5 }] }
|
|
304
329
|
```
|
|
305
330
|
|
|
306
|
-
Empty means everything validates. Pass `schema:` a loaded schema
|
|
307
|
-
touches the network — handy for checking a
|
|
308
|
-
|
|
331
|
+
Empty means everything validates. Pass `schema:` a *loaded* schema (not a path)
|
|
332
|
+
and nothing touches the network — handy for checking a proposed subgraph before
|
|
333
|
+
it's live:
|
|
309
334
|
|
|
310
335
|
```ruby
|
|
311
336
|
GraphWeaver.check_queries(schema: GraphWeaver::SchemaLoader.load("proposed.graphql"))
|
|
312
337
|
```
|
|
313
338
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
([federation](federation.md#the-routing-table)).
|
|
339
|
+
Left off, it re-introspects the url the dump records — and when that dump is a
|
|
340
|
+
composed supergraph, each error also names the subgraphs behind the type it
|
|
341
|
+
points at ([federation](federation.md#the-routing-table)).
|
|
318
342
|
|
|
319
343
|
## Sorbet, with or without
|
|
320
344
|
|
data/docs/logging.md
CHANGED
|
@@ -14,8 +14,9 @@ What logs at which level — pick the level, get the story:
|
|
|
14
14
|
| Level | What you see |
|
|
15
15
|
|-------|--------------|
|
|
16
16
|
| `debug` | the wire: query + variables per call (long queries truncated), response status/bytes, request timing, connection open/drop, dynamically parsed modules |
|
|
17
|
-
| `info` | schema introspection (with timing) and cache hits/misses, generated files written and any unregistered scalars, query modules loaded |
|
|
18
|
-
| `warn` | every GraphWeaver error raised — `TransportError`, `ServerError`, `QueryError`, `ValidationError`, `TypeError` |
|
|
17
|
+
| `info` | schema introspection (with timing) and cache hits/misses, the transport a client built, generated files written and any unregistered scalars, query modules loaded, a retry's wait and attempt number — and in development, what's being watched and what a save regenerated |
|
|
18
|
+
| `warn` | every GraphWeaver error raised — `TransportError`, `ServerError`, `QueryError`, `ValidationError`, `TypeError` — registrations the schema being generated against can't match, a retry skipped because the operation was a mutation, and every fetch the test router answered with fabricated data |
|
|
19
|
+
| `error` | development only: a `.graphql` edit that won't compile, with its file and position — the modules already loaded keep serving |
|
|
19
20
|
|
|
20
21
|
Every line carries `graph_weaver` as the progname, so formatter-based
|
|
21
22
|
filtering works out of the box. Wire lines are tagged
|
|
@@ -24,8 +25,37 @@ name — so a request's lines stay paired when threads interleave.
|
|
|
24
25
|
|
|
25
26
|
**PII note**: queries, variables, and response sizes appear at debug
|
|
26
27
|
only — variables can carry user data, so keep production loggers at
|
|
27
|
-
info or above
|
|
28
|
-
|
|
28
|
+
info or above. Auth headers never log at any level.
|
|
29
|
+
|
|
30
|
+
## Filtered variables
|
|
31
|
+
|
|
32
|
+
Debug gets switched on during an incident, which is exactly when a
|
|
33
|
+
`login(password:)` mutation's variables must not land in the log. So the
|
|
34
|
+
values of sensitive keys are replaced with `[FILTERED]` before the line is
|
|
35
|
+
written — at any depth, including inside input objects.
|
|
36
|
+
|
|
37
|
+
In Rails you configure nothing: the railtie adopts the app's own
|
|
38
|
+
`config.filter_parameters`, so GraphWeaver scrubs whatever the request logs
|
|
39
|
+
already scrub.
|
|
40
|
+
|
|
41
|
+
Everywhere else, one list:
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
GraphWeaver.filter_parameters = [:password, /token/]
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Strings and Symbols match as case-insensitive substrings — `:token` covers
|
|
48
|
+
`apiToken` — and Regexps match themselves. The default is `[:password,
|
|
49
|
+
:token, :secret, :authorization]`, which covers the usual names before
|
|
50
|
+
anyone configures anything; assigning replaces it rather than adding to it,
|
|
51
|
+
and `[]` turns filtering off. Anything answering `#filter(hash)` is used
|
|
52
|
+
as-is, which is how the railtie hands over an
|
|
53
|
+
`ActiveSupport::ParameterFilter`.
|
|
54
|
+
|
|
55
|
+
The same list scrubs error messages, which reach the log at `warn` rather
|
|
56
|
+
than `debug`: a variable, input field, or entity key whose name is filtered
|
|
57
|
+
is rejected with `[FILTERED]` in place of the value — everything else keeps
|
|
58
|
+
quoting it, since `expected an Int, got "lots"` is the whole diagnosis.
|
|
29
59
|
|
|
30
60
|
## Instrumentation
|
|
31
61
|
|
data/docs/real_world.md
CHANGED
|
@@ -19,10 +19,10 @@ require "graph_weaver"
|
|
|
19
19
|
# in a header, so a stale dump says where it came from.
|
|
20
20
|
github = GraphWeaver.new("https://api.github.com/graphql", auth: `gh auth token`.strip, cache: true)
|
|
21
21
|
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
|
|
22
|
+
# GitHub's DateTime needs no registration — it is one of the names the
|
|
23
|
+
# registry knows (docs/scalars.md). A scalar of your own would go here;
|
|
24
|
+
# registrations are global and codegen-time, so one line types your
|
|
25
|
+
# console and your checked-in code identically.
|
|
26
26
|
|
|
27
27
|
RepoQuery = github.parse(<<~GRAPHQL)
|
|
28
28
|
query($owner: String!, $name: String!) {
|