Skip to content

Commit c67a102

Browse files
committed
GetArgumentValues: public version of getArgumentValues()
to write custom validation rules, sometimes it want to access field's argument values, but getArgumentValues() is private. this creates public version of getArgumentValues() to access from those validation rules.
1 parent fb3402f commit c67a102

File tree

2 files changed

+74
-0
lines changed

2 files changed

+74
-0
lines changed

graphql_test.go

+63
Original file line numberDiff line numberDiff line change
@@ -327,3 +327,66 @@ func TestQueryWithCustomRule(t *testing.T) {
327327
}
328328
}
329329
}
330+
331+
// TestCustomRuleWithArgs tests graphql.GetArgumentValues() be able to access
332+
// field's argument values from custom validation rule.
333+
func TestCustomRuleWithArgs(t *testing.T) {
334+
fieldDef, ok := testutil.StarWarsSchema.QueryType().Fields()["human"]
335+
if !ok {
336+
t.Fatal("can't retrieve \"human\" field definition")
337+
}
338+
339+
// a custom validation rule to extract argument values of "human" field.
340+
var actual map[string]interface{}
341+
enter := func(p visitor.VisitFuncParams) (string, interface{}) {
342+
// only interested in "human" field.
343+
fieldNode, ok := p.Node.(*ast.Field)
344+
if !ok || fieldNode.Name == nil || fieldNode.Name.Value != "human" {
345+
return visitor.ActionNoChange, nil
346+
}
347+
// extract argument values by graphql.GetArgumentValues().
348+
actual = graphql.GetArgumentValues(fieldDef.Args, fieldNode.Arguments, nil)
349+
return visitor.ActionNoChange, nil
350+
}
351+
checkHumanArgs := func(context *graphql.ValidationContext) *graphql.ValidationRuleInstance {
352+
return &graphql.ValidationRuleInstance{
353+
VisitorOpts: &visitor.VisitorOptions{
354+
KindFuncMap: map[string]visitor.NamedVisitFuncs{
355+
kinds.Field: {Enter: enter},
356+
},
357+
},
358+
}
359+
}
360+
361+
for _, tc := range []struct {
362+
query string
363+
expected map[string]interface{}
364+
}{
365+
{
366+
`query { human(id: "1000") { name } }`,
367+
map[string]interface{}{"id": "1000"},
368+
},
369+
{
370+
`query { human(id: "1002") { name } }`,
371+
map[string]interface{}{"id": "1002"},
372+
},
373+
{
374+
`query { human(id: "9999") { name } }`,
375+
map[string]interface{}{"id": "9999"},
376+
},
377+
} {
378+
actual = nil
379+
params := graphql.Params{
380+
Schema: testutil.StarWarsSchema,
381+
RequestString: tc.query,
382+
ValidationRules: append(graphql.SpecifiedRules, checkHumanArgs),
383+
}
384+
result := graphql.Do(params)
385+
if len(result.Errors) > 0 {
386+
t.Fatalf("wrong result, unexpected errors: %v", result.Errors)
387+
}
388+
if !reflect.DeepEqual(actual, tc.expected) {
389+
t.Fatalf("unexpected result: want=%+v got=%+v", tc.expected, actual)
390+
}
391+
}
392+
}

values.go

+11
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,17 @@ func getArgumentValues(
6767
return results
6868
}
6969

70+
// GetArgumentValues prepares an object map of argument values given a list of
71+
// argument definitions and list of argument AST nodes.
72+
//
73+
// This is an exported version of getArgumentValues(), to ease writing custom
74+
// validation rules.
75+
func GetArgumentValues(
76+
argDefs []*Argument, argASTs []*ast.Argument,
77+
variableValues map[string]interface{}) map[string]interface{} {
78+
return getArgumentValues(argDefs, argASTs, variableValues)
79+
}
80+
7081
// Given a variable definition, and any value of input, return a value which
7182
// adheres to the variable definition, or throw an error.
7283
func getVariableValue(schema Schema, definitionAST *ast.VariableDefinition, input interface{}) (interface{}, error) {

0 commit comments

Comments
 (0)