Skip to content

Commit b29a977

Browse files
authored
graphql: Allow user to define and pass arguments to fields. (#5562)
This would allow users to pass in arguments to fields of remote endpoints.
1 parent 476c7aa commit b29a977

File tree

10 files changed

+487
-24
lines changed

10 files changed

+487
-24
lines changed

graphql/e2e/custom_logic/cmd/graphqlresponse.yaml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,34 @@
8989
country(code: ID!): Country!
9090
}
9191
92+
- name: "argsonfields"
93+
description: "Test case to check args on fields can be passed by Dgraph"
94+
schema: |
95+
type Country {
96+
code(size: Int!): String
97+
name: String
98+
}
99+
100+
type Query {
101+
country(code: ID!): Country!
102+
}
103+
request: |
104+
query($id: ID!) { country(code: $id) {
105+
code(size: 100)
106+
name
107+
}}
108+
variables: |
109+
{"id":"BI"}
110+
response: |
111+
{
112+
"data":{
113+
"country":{
114+
"name":"Burundi",
115+
"code":"BI"
116+
}
117+
}
118+
}
119+
92120
- name: "validcountrywitherror"
93121
description: "Test case to validate dgraph can handle both valid data and error"
94122
schema: |

graphql/e2e/custom_logic/cmd/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,6 +1154,7 @@ func main() {
11541154
// for queries
11551155
vsch := graphql.MustParseSchema(graphqlResponses["validcountry"].Schema, &query{})
11561156
http.Handle("/validcountry", &relay.Handler{Schema: vsch})
1157+
http.HandleFunc("/argsonfields", commonGraphqlHandler("argsonfields"))
11571158
http.HandleFunc("/validcountrywitherror", commonGraphqlHandler("validcountrywitherror"))
11581159
http.HandleFunc("/graphqlerr", commonGraphqlHandler("graphqlerr"))
11591160
http.Handle("/validcountries", &relay.Handler{

graphql/e2e/custom_logic/custom_logic_test.go

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const (
4949
director: [MovieDirector]
5050
}
5151
type Country @remote {
52-
code: String
52+
code(size: Int): String
5353
name: String
5454
states: [State]
5555
std: Int
@@ -1209,6 +1209,37 @@ func TestCustomLogicGraphql(t *testing.T) {
12091209
require.JSONEq(t, string(result.Data), `{"getCountry1":{"code":"BI","name":"Burundi"}}`)
12101210
}
12111211

1212+
func TestCustomLogicGraphqlWithArgumentsOnFields(t *testing.T) {
1213+
schema := customTypes + `
1214+
type Query {
1215+
getCountry2(id: ID!): Country!
1216+
@custom(
1217+
http: {
1218+
url: "http://mock:8888/argsonfields"
1219+
method: "POST"
1220+
forwardHeaders: ["Content-Type"]
1221+
graphql: "query($id: ID!) { country(code: $id) }"
1222+
}
1223+
)
1224+
}`
1225+
updateSchemaRequireNoGQLErrors(t, schema)
1226+
time.Sleep(2 * time.Second)
1227+
query := `
1228+
query {
1229+
getCountry2(id: "BI"){
1230+
code(size: 100)
1231+
name
1232+
}
1233+
}`
1234+
params := &common.GraphQLParams{
1235+
Query: query,
1236+
}
1237+
1238+
result := params.ExecuteAsPost(t, alphaURL)
1239+
common.RequireNoGQLErrors(t, result)
1240+
require.JSONEq(t, string(result.Data), `{"getCountry2":{"code":"BI","name":"Burundi"}}`)
1241+
}
1242+
12121243
func TestCustomLogicGraphqlWithError(t *testing.T) {
12131244
schema := customTypes + `
12141245
type Query {

graphql/schema/custom_http_config_test.yaml

Lines changed: 88 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,85 @@
4646
{ "id": "0x1" }
4747
4848
-
49-
name: "custom mutation"
49+
name: "custom query with arguments on fields"
50+
type: "query"
51+
gqlschema: |
52+
input ExactFilter {
53+
eq: String
54+
}
55+
56+
input MyFilter {
57+
ids: ID
58+
name: ExactFilter
59+
}
60+
61+
type Country @remote {
62+
code(first: Int!, filter: MyFilter): String
63+
name: String
64+
}
65+
66+
type Query {
67+
getCountry1(id: ID!): Country! @custom(http: {
68+
url: "http://google.com/validcountry",
69+
method: "POST",
70+
forwardHeaders: ["Content-Type"],
71+
graphql: "query($id: ID!) { country(code: $id) }",
72+
skipIntrospection: true
73+
})
74+
}
75+
gqlquery: |
76+
query {
77+
getCountry1(id: "0x1") {
78+
name
79+
code(first: 10, filter: {ids: "0x123", name: { eq: "github" }})
80+
}
81+
}
82+
remoteschema: |
83+
input ExactFilter {
84+
eq: String
85+
}
86+
87+
input MyFilter {
88+
ids: ID
89+
name: ExactFilter
90+
}
91+
92+
type Country @remote {
93+
code(first: Int!, filter: MyFilter): String
94+
name: String
95+
}
96+
97+
type Query {
98+
country(code: ID!): Country! @custom(http: {
99+
url: "http://google.com/validcountry",
100+
method: "POST",
101+
graphql: "query($code: ID!) { country(code: $code) }",
102+
skipIntrospection: true
103+
})
104+
}
105+
remotequery: |-
106+
query($id: ID!) { country(code: $id) {
107+
name
108+
code(first: 10, filter: {ids:"0x123",name:{eq:"github"}})
109+
}}
110+
remotevariables: |-
111+
{ "id": "0x1" }
112+
113+
-
114+
name: "custom mutation with arguments on field"
50115
type: "mutation"
51116
gqlschema: |
117+
input ExactFilter {
118+
eq: String
119+
}
120+
121+
input MyFilter {
122+
ids: ID
123+
name: ExactFilter
124+
}
125+
52126
type Country @remote {
53-
code: String
127+
code(get: Int!, choose: MyFilter): String
54128
name: String
55129
states: [State]
56130
std: Int
@@ -84,7 +158,7 @@
84158
gqlquery: |
85159
mutation addCountry1($input: CountryInput!) {
86160
addCountry1(input: $input) {
87-
code
161+
code(get: 10, choose: {ids: "0x123", name: { eq: "github" }})
88162
name
89163
states {
90164
code
@@ -110,8 +184,17 @@
110184
}
111185
}
112186
remoteschema: |
187+
input ExactFilter {
188+
eq: String
189+
}
190+
191+
input MyFilter {
192+
ids: ID
193+
name: ExactFilter
194+
}
195+
113196
type Country {
114-
code: String
197+
code(get: Int!, choose: MyFilter): String
115198
name: String
116199
states: [State]
117200
std: Int
@@ -144,7 +227,7 @@
144227
}
145228
remotequery: |-
146229
mutation($input: CountryInput!) { setCountry(country: $input) {
147-
code
230+
code(get: 10, choose: {ids:"0x123",name:{eq:"github"}})
148231
name
149232
states{
150233
code

graphql/schema/gqlschema.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,13 +326,13 @@ func copyAstFieldDef(src *ast.FieldDefinition) *ast.FieldDefinition {
326326
var dirs ast.DirectiveList
327327
dirs = append(dirs, src.Directives...)
328328

329-
// Lets leave out copying the arguments as types in input schemas are not supposed to contain
330-
// them. We add arguments for filters and order statements later.
329+
// We add arguments for filters and order statements later.
331330
dst := &ast.FieldDefinition{
332331
Name: src.Name,
333332
DefaultValue: src.DefaultValue,
334333
Type: src.Type,
335334
Directives: dirs,
335+
Arguments: src.Arguments,
336336
Position: src.Position,
337337
}
338338
return dst
@@ -1240,6 +1240,7 @@ func createField(schema *ast.Schema, fld *ast.FieldDefinition) *ast.FieldDefinit
12401240
newFldType := *fld.Type
12411241
newFld.Type = &newFldType
12421242
newFld.Directives = nil
1243+
newFld.Arguments = nil
12431244
return &newFld
12441245
}
12451246

graphql/schema/gqlschema_test.yml

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,16 +62,6 @@ invalid_schemas:
6262
{"message": "Type A; Field f: Nested lists are invalid.", "locations": [{"line":2, "column": 3}]}
6363
]
6464

65-
-
66-
name: "There shoudnt be arguments on any field"
67-
input: |
68-
type T {
69-
f(a: Int): String
70-
}
71-
errlist: [
72-
{"message": "Type T; Field f: You can't give arguments to fields.", "locations": [{"line": 2, "column": 3}]}
73-
]
74-
7565
-
7666
name: "Enum indexes clash trigram and regexp"
7767
input: |
@@ -1903,6 +1893,15 @@ invalid_schemas:
19031893
"locations":[{"line":1, "column":11}]},
19041894
]
19051895

1896+
1897+
- name: "There shoudnt be any reserved arguments on any field"
1898+
input: |
1899+
type T {
1900+
f(first: Int): String
1901+
}
1902+
errlist: [
1903+
{"message": "Type T; Field f: can't have first as an argument because it is a reserved argument.", "locations": [{"line": 2, "column": 3}]}]
1904+
19061905
- name: "remote type with @custom directives on fields shouldn't be allowed."
19071906
description: "Remote types are not resolved further currently, hence they shouldn't have
19081907
fields with @custom directive on them."

graphql/schema/rules.go

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -694,12 +694,22 @@ func fieldArgumentCheck(typ *ast.Definition, field *ast.FieldDefinition) *gqlerr
694694
if isQueryOrMutationType(typ) {
695695
return nil
696696
}
697-
if field.Arguments != nil {
698-
return gqlerror.ErrorPosf(
699-
field.Position,
700-
"Type %s; Field %s: You can't give arguments to fields.",
701-
typ.Name, field.Name,
702-
)
697+
// We don't need to verify the argument names for fields which are part of a remote type as
698+
// we don't add any of our own arguments to them.
699+
remote := typ.Directives.ForName(remoteDirective)
700+
if remote != nil {
701+
return nil
702+
}
703+
for _, arg := range field.Arguments {
704+
if isReservedArgument(arg.Name) {
705+
return gqlerror.ErrorPosf(
706+
field.Position,
707+
"Type %s; Field %s: can't have %s as an argument because it is a reserved "+
708+
"argument.",
709+
typ.Name, field.Name, arg.Name,
710+
)
711+
712+
}
703713
}
704714
return nil
705715
}
@@ -1649,6 +1659,14 @@ func isScalar(s string) bool {
16491659
return ok
16501660
}
16511661

1662+
func isReservedArgument(name string) bool {
1663+
switch name {
1664+
case "first", "offset", "filter", "order":
1665+
return true
1666+
}
1667+
return false
1668+
}
1669+
16521670
func isReservedKeyWord(name string) bool {
16531671
if isScalar(name) || isQueryOrMutation(name) || name == "uid" {
16541672
return true
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
interface Abstract {
2+
id: ID!
3+
name(random: Int!, size: String): String!
4+
}
5+
6+
type Message implements Abstract {
7+
content(pick: Int!, name: String): String!
8+
author: String
9+
datePosted: DateTime
10+
}

0 commit comments

Comments
 (0)