Skip to content

Commit 4422735

Browse files
monicatangfacebook-github-bot
authored andcommitted
validate that field arguments passed to relay resolvers are defined
Summary: ## Context When compiling relay resolvers we are missing validation on undefined global variables (particularly field args) within resolvers. ## This diff Checks field arguments stored in the RelayResolverMetadata during global variable validation. I've also added a test in relay-transforms that checks the result of the relay_resolvers transform when there is an alias applied for a scalar relay resolver. When compiling relay resolvers we are missing validation on undefined global variables (particularly field args) within resolvers. This change checks field arguments stored in the RelayResolverMetadata during global variable validation. Reviewed By: tyao1 Differential Revision: D50624904 fbshipit-source-id: e7fb5a243c902075083753316cc8fc3ced74fc80
1 parent 2bc89ad commit 4422735

13 files changed

+158
-668
lines changed

compiler/crates/graphql-ir/src/associated_data.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,13 @@ macro_rules! associated_data_impl {
101101
#[allow(dead_code)]
102102
pub fn find(directives: &[$crate::Directive]) -> Option<&Self> {
103103
use $crate::reexport::NamedItem;
104-
directives.named(Self::directive_name()).map(|directive| {
104+
directives
105+
.named(Self::directive_name())
106+
.map(|directive| $name::from(directive).unwrap())
107+
}
108+
109+
pub fn from(directive: &$crate::Directive) -> Option<&Self> {
110+
Some(
105111
directive
106112
.data
107113
.as_ref()
@@ -115,8 +121,8 @@ macro_rules! associated_data_impl {
115121
"data on @__",
116122
stringify!($name),
117123
" directive not of right type"
118-
))
119-
})
124+
)),
125+
)
120126
}
121127
}
122128
};

compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/relay-resolver-with-undefined-field-and-fragment-args.invalid.expected

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,15 @@ extend type User {
2323
pop_star_name(field_arg: Int, includeName: Boolean!): String @relay_resolver(fragment_name: "relayResolverWithUndefinedFieldAndFragmentArgsFragment_name", import_path: "PopStarNameResolver")
2424
}
2525
==================================== ERROR ====================================
26-
✖︎ Operation 'relayResolverWithUndefinedFieldAndFragmentArgsQuery' references undefined variable: '$undefined_fragment_arg'.
26+
✖︎ Operation 'relayResolverWithUndefinedFieldAndFragmentArgsQuery' references undefined variables: '$undefined_field_arg', '$undefined_fragment_arg'.
27+
28+
relay-resolver-with-undefined-field-and-fragment-args.invalid.graphql:10:28
29+
9 │ fragment relayResolverWithUndefinedFieldAndFragmentArgs_user on User {
30+
10 │ pop_star_name(field_arg: $undefined_field_arg, includeName: $undefined_fragment_arg)
31+
│ ^^^^^^^^^^^^^^^^^^^^
32+
11 │ }
33+
34+
ℹ︎ related location
2735

2836
relay-resolver-with-undefined-field-and-fragment-args.invalid.graphql:10:63
2937
9 │ fragment relayResolverWithUndefinedFieldAndFragmentArgs_user on User {
Lines changed: 8 additions & 315 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
==================================== INPUT ====================================
2-
# TODO T160746170 expected to throw
2+
# expected-to-throw
33

44
query relayResolverWithUndefinedFieldArgsLinkedFieldQuery {
55
node(id: "SOME_ID") {
@@ -17,318 +17,11 @@ fragment relayResolverWithUndefinedFieldArgsLinkedField_PopStar on User {
1717
extend type User {
1818
pop_star(name: String): User @relay_resolver(import_path: "./path/to/PopStarResolver.js")
1919
}
20-
==================================== OUTPUT ===================================
21-
{
22-
"fragment": {
23-
"argumentDefinitions": [
24-
{
25-
"defaultValue": null,
26-
"kind": "LocalArgument",
27-
"name": "id"
28-
}
29-
],
30-
"kind": "Fragment",
31-
"metadata": null,
32-
"name": "ClientEdgeQuery_relayResolverWithUndefinedFieldArgsLinkedField_PopStar_pop_star",
33-
"selections": [
34-
{
35-
"alias": null,
36-
"args": [
37-
{
38-
"kind": "Variable",
39-
"name": "id",
40-
"variableName": "id"
41-
}
42-
],
43-
"concreteType": null,
44-
"kind": "LinkedField",
45-
"name": "node",
46-
"plural": false,
47-
"selections": [
48-
{
49-
"args": null,
50-
"kind": "FragmentSpread",
51-
"name": "RefetchableClientEdgeQuery_relayResolverWithUndefinedFieldArgsLinkedField_PopStar_pop_star"
52-
}
53-
],
54-
"storageKey": null
55-
}
56-
],
57-
"type": "Query",
58-
"abstractKey": null
59-
},
60-
"kind": "Request",
61-
"operation": {
62-
"argumentDefinitions": [
63-
{
64-
"defaultValue": null,
65-
"kind": "LocalArgument",
66-
"name": "id"
67-
}
68-
],
69-
"kind": "Operation",
70-
"name": "ClientEdgeQuery_relayResolverWithUndefinedFieldArgsLinkedField_PopStar_pop_star",
71-
"selections": [
72-
{
73-
"alias": null,
74-
"args": [
75-
{
76-
"kind": "Variable",
77-
"name": "id",
78-
"variableName": "id"
79-
}
80-
],
81-
"concreteType": null,
82-
"kind": "LinkedField",
83-
"name": "node",
84-
"plural": false,
85-
"selections": [
86-
{
87-
"alias": null,
88-
"args": null,
89-
"kind": "ScalarField",
90-
"name": "__typename",
91-
"storageKey": null
92-
},
93-
{
94-
"alias": null,
95-
"args": null,
96-
"kind": "ScalarField",
97-
"name": "id",
98-
"storageKey": null
99-
}
100-
],
101-
"storageKey": null
102-
}
103-
]
104-
},
105-
"params": {
106-
"cacheID": "d5903316ee00d1bf3d4368d1c75c827e",
107-
"id": null,
108-
"metadata": {},
109-
"name": "ClientEdgeQuery_relayResolverWithUndefinedFieldArgsLinkedField_PopStar_pop_star",
110-
"operationKind": "query",
111-
"text": null
112-
}
113-
}
114-
115-
QUERY:
116-
117-
query ClientEdgeQuery_relayResolverWithUndefinedFieldArgsLinkedField_PopStar_pop_star(
118-
$id: ID!
119-
) {
120-
node(id: $id) {
121-
__typename
122-
...RefetchableClientEdgeQuery_relayResolverWithUndefinedFieldArgsLinkedField_PopStar_pop_star
123-
id
124-
}
125-
}
126-
127-
fragment RefetchableClientEdgeQuery_relayResolverWithUndefinedFieldArgsLinkedField_PopStar_pop_star on User {
128-
id
129-
}
130-
131-
132-
{
133-
"fragment": {
134-
"argumentDefinitions": [],
135-
"kind": "Fragment",
136-
"metadata": null,
137-
"name": "relayResolverWithUndefinedFieldArgsLinkedFieldQuery",
138-
"selections": [
139-
{
140-
"alias": null,
141-
"args": [
142-
{
143-
"kind": "Literal",
144-
"name": "id",
145-
"value": "SOME_ID"
146-
}
147-
],
148-
"concreteType": null,
149-
"kind": "LinkedField",
150-
"name": "node",
151-
"plural": false,
152-
"selections": [
153-
{
154-
"args": null,
155-
"kind": "FragmentSpread",
156-
"name": "relayResolverWithUndefinedFieldArgsLinkedField_PopStar"
157-
}
158-
],
159-
"storageKey": "node(id:\"SOME_ID\")"
160-
}
161-
],
162-
"type": "Query",
163-
"abstractKey": null
164-
},
165-
"kind": "Request",
166-
"operation": {
167-
"argumentDefinitions": [],
168-
"kind": "Operation",
169-
"name": "relayResolverWithUndefinedFieldArgsLinkedFieldQuery",
170-
"selections": [
171-
{
172-
"alias": null,
173-
"args": [
174-
{
175-
"kind": "Literal",
176-
"name": "id",
177-
"value": "SOME_ID"
178-
}
179-
],
180-
"concreteType": null,
181-
"kind": "LinkedField",
182-
"name": "node",
183-
"plural": false,
184-
"selections": [
185-
{
186-
"alias": null,
187-
"args": null,
188-
"kind": "ScalarField",
189-
"name": "__typename",
190-
"storageKey": null
191-
},
192-
{
193-
"kind": "InlineFragment",
194-
"selections": [
195-
{
196-
"name": "pop_star",
197-
"args": [
198-
{
199-
"kind": "Variable",
200-
"name": "name",
201-
"variableName": "undefined"
202-
}
203-
],
204-
"fragment": null,
205-
"kind": "RelayResolver",
206-
"storageKey": null,
207-
"isOutputType": false
208-
}
209-
],
210-
"type": "User",
211-
"abstractKey": null
212-
},
213-
{
214-
"alias": null,
215-
"args": null,
216-
"kind": "ScalarField",
217-
"name": "id",
218-
"storageKey": null
219-
}
220-
],
221-
"storageKey": "node(id:\"SOME_ID\")"
222-
}
223-
]
224-
},
225-
"params": {
226-
"cacheID": "e8583c1b54f5e17064d894b8094a5a68",
227-
"id": null,
228-
"metadata": {},
229-
"name": "relayResolverWithUndefinedFieldArgsLinkedFieldQuery",
230-
"operationKind": "query",
231-
"text": null
232-
}
233-
}
234-
235-
QUERY:
236-
237-
query relayResolverWithUndefinedFieldArgsLinkedFieldQuery {
238-
node(id: "SOME_ID") {
239-
__typename
240-
id
241-
}
242-
}
243-
20+
==================================== ERROR ====================================
21+
✖︎ Operation 'relayResolverWithUndefinedFieldArgsLinkedFieldQuery' references undefined variable: '$undefined'.
24422

245-
{
246-
"argumentDefinitions": [],
247-
"kind": "Fragment",
248-
"metadata": {
249-
"refetch": {
250-
"connection": null,
251-
"fragmentPathInResult": [
252-
"node"
253-
],
254-
"operation": require('ClientEdgeQuery_relayResolverWithUndefinedFieldArgsLinkedField_PopStar_pop_star.graphql'),
255-
"identifierInfo": {
256-
"identifierField": "id",
257-
"identifierQueryVariableName": "id"
258-
}
259-
}
260-
},
261-
"name": "RefetchableClientEdgeQuery_relayResolverWithUndefinedFieldArgsLinkedField_PopStar_pop_star",
262-
"selections": [
263-
{
264-
"alias": null,
265-
"args": null,
266-
"kind": "ScalarField",
267-
"name": "id",
268-
"storageKey": null
269-
}
270-
],
271-
"type": "User",
272-
"abstractKey": null
273-
}
274-
275-
{
276-
"argumentDefinitions": [
277-
{
278-
"kind": "RootArgument",
279-
"name": "undefined"
280-
}
281-
],
282-
"kind": "Fragment",
283-
"metadata": {
284-
"hasClientEdges": true
285-
},
286-
"name": "relayResolverWithUndefinedFieldArgsLinkedField_PopStar",
287-
"selections": [
288-
{
289-
"kind": "ClientEdgeToServerObject",
290-
"operation": require('ClientEdgeQuery_relayResolverWithUndefinedFieldArgsLinkedField_PopStar_pop_star.graphql'),
291-
"backingField": {
292-
"alias": null,
293-
"args": [
294-
{
295-
"kind": "Variable",
296-
"name": "name",
297-
"variableName": "undefined"
298-
}
299-
],
300-
"fragment": null,
301-
"kind": "RelayResolver",
302-
"name": "pop_star",
303-
"resolverModule": require('PopStarResolver'),
304-
"path": "pop_star"
305-
},
306-
"linkedField": {
307-
"alias": null,
308-
"args": [
309-
{
310-
"kind": "Variable",
311-
"name": "name",
312-
"variableName": "undefined"
313-
}
314-
],
315-
"concreteType": "User",
316-
"kind": "LinkedField",
317-
"name": "pop_star",
318-
"plural": false,
319-
"selections": [
320-
{
321-
"alias": null,
322-
"args": null,
323-
"kind": "ScalarField",
324-
"name": "id",
325-
"storageKey": null
326-
}
327-
],
328-
"storageKey": null
329-
}
330-
}
331-
],
332-
"type": "User",
333-
"abstractKey": null
334-
}
23+
relay-resolver-with-undefined-field-args-linked-field.invalid.graphql:10:18
24+
9 │ fragment relayResolverWithUndefinedFieldArgsLinkedField_PopStar on User {
25+
10 │ pop_star(name: $undefined) @waterfall {
26+
│ ^^^^^^^^^^
27+
11 │ id

compiler/crates/relay-compiler/tests/compile_relay_artifacts/fixtures/relay-resolver-with-undefined-field-args-linked-field.invalid.graphql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# TODO T160746170 expected to throw
1+
# expected-to-throw
22

33
query relayResolverWithUndefinedFieldArgsLinkedFieldQuery {
44
node(id: "SOME_ID") {

0 commit comments

Comments
 (0)