Skip to content

Commit 0bb7429

Browse files
authored
add specifiedBy directive (graph-gophers#532)
1 parent 4878856 commit 0bb7429

File tree

5 files changed

+155
-10
lines changed

5 files changed

+155
-10
lines changed

example/social/introspect.json

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,29 @@
7070
"INLINE_FRAGMENT"
7171
],
7272
"name": "skip"
73+
},
74+
{
75+
"args": [
76+
{
77+
"defaultValue": null,
78+
"description": "The URL should point to a human-readable specification of the data format, serialization, and coercion rules.",
79+
"name": "url",
80+
"type": {
81+
"kind": "NON_NULL",
82+
"name": null,
83+
"ofType": {
84+
"kind": "SCALAR",
85+
"name": "String",
86+
"ofType": null
87+
}
88+
}
89+
}
90+
],
91+
"description": "Provides a scalar specification URL for specifying the behavior of custom scalar types.",
92+
"locations": [
93+
"SCALAR"
94+
],
95+
"name": "specifiedBy"
7396
}
7497
],
7598
"mutationType": null,
@@ -1339,6 +1362,18 @@
13391362
"name": "__Type",
13401363
"ofType": null
13411364
}
1365+
},
1366+
{
1367+
"args": [],
1368+
"deprecationReason": null,
1369+
"description": null,
1370+
"isDeprecated": false,
1371+
"name": "specifiedByURL",
1372+
"type": {
1373+
"kind": "SCALAR",
1374+
"name": "String",
1375+
"ofType": null
1376+
}
13421377
}
13431378
],
13441379
"inputFields": null,
@@ -1408,4 +1443,4 @@
14081443
}
14091444
]
14101445
}
1411-
}
1446+
}

example/starwars/introspect.json

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,29 @@
7070
"INLINE_FRAGMENT"
7171
],
7272
"name": "skip"
73+
},
74+
{
75+
"args": [
76+
{
77+
"defaultValue": null,
78+
"description": "The URL should point to a human-readable specification of the data format, serialization, and coercion rules.",
79+
"name": "url",
80+
"type": {
81+
"kind": "NON_NULL",
82+
"name": null,
83+
"ofType": {
84+
"kind": "SCALAR",
85+
"name": "String",
86+
"ofType": null
87+
}
88+
}
89+
}
90+
],
91+
"description": "Provides a scalar specification URL for specifying the behavior of custom scalar types.",
92+
"locations": [
93+
"SCALAR"
94+
],
95+
"name": "specifiedBy"
7396
}
7497
],
7598
"mutationType": {
@@ -1981,6 +2004,18 @@
19812004
"name": "__Type",
19822005
"ofType": null
19832006
}
2007+
},
2008+
{
2009+
"args": [],
2010+
"deprecationReason": null,
2011+
"description": null,
2012+
"isDeprecated": false,
2013+
"name": "specifiedByURL",
2014+
"type": {
2015+
"kind": "SCALAR",
2016+
"name": "String",
2017+
"ofType": null
2018+
}
19842019
}
19852020
],
19862021
"inputFields": null,
@@ -2050,4 +2085,4 @@
20502085
}
20512086
]
20522087
}
2053-
}
2088+
}

graphql_test.go

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,7 @@ func TestEmbeddedStruct(t *testing.T) {
626626
type Query {
627627
course: Course!
628628
}
629-
629+
630630
type Course {
631631
name: String!
632632
createdAt: String!
@@ -1494,6 +1494,40 @@ func TestDeprecatedDirective(t *testing.T) {
14941494
})
14951495
}
14961496

1497+
func TestSpecifiedByDirective(t *testing.T) {
1498+
gqltesting.RunTests(t, []*gqltesting.Test{
1499+
{
1500+
Schema: graphql.MustParseSchema(`
1501+
schema {
1502+
query: Query
1503+
}
1504+
type Query {
1505+
}
1506+
scalar UUID @specifiedBy(
1507+
url: "https://tools.ietf.org/html/rfc4122"
1508+
)
1509+
`, &struct{}{}),
1510+
Query: `
1511+
query {
1512+
__type(name: "UUID") {
1513+
name
1514+
specifiedByURL
1515+
}
1516+
}
1517+
`,
1518+
Variables: map[string]interface{}{},
1519+
ExpectedResult: `
1520+
{
1521+
"__type": {
1522+
"name": "UUID",
1523+
"specifiedByURL": "https://tools.ietf.org/html/rfc4122"
1524+
}
1525+
}
1526+
`,
1527+
},
1528+
})
1529+
}
1530+
14971531
type testBadEnumResolver struct{}
14981532

14991533
func (r *testBadEnumResolver) Hero() *testBadEnumCharacterResolver {
@@ -1854,11 +1888,11 @@ func TestTypeName(t *testing.T) {
18541888
}
18551889
}
18561890
}
1857-
1891+
18581892
fragment Droid on Droid {
18591893
name
18601894
__typename
1861-
}
1895+
}
18621896
`,
18631897
RawResponse: true,
18641898
ExpectedResult: `{"hero":{"__typename":"Droid","name":"R2-D2"}}`,
@@ -2478,6 +2512,26 @@ func TestIntrospection(t *testing.T) {
24782512
}
24792513
}
24802514
]
2515+
},
2516+
{
2517+
"name": "specifiedBy",
2518+
"description": "Provides a scalar specification URL for specifying the behavior of custom scalar types.",
2519+
"locations": [
2520+
"SCALAR"
2521+
],
2522+
"args": [
2523+
{
2524+
"name": "url",
2525+
"description": "The URL should point to a human-readable specification of the data format, serialization, and coercion rules.",
2526+
"type": {
2527+
"kind": "NON_NULL",
2528+
"ofType": {
2529+
"kind": "SCALAR",
2530+
"name": "String"
2531+
}
2532+
}
2533+
}
2534+
]
24812535
}
24822536
]
24832537
}
@@ -3800,7 +3854,7 @@ func TestPanicAmbiguity(t *testing.T) {
38003854
name: String!
38013855
university: University!
38023856
}
3803-
3857+
38043858
type University {
38053859
name: String!
38063860
}
@@ -4300,11 +4354,11 @@ func TestQueryVariablesValidation(t *testing.T) {
43004354
required: String!
43014355
optional: String
43024356
}
4303-
4357+
43044358
type SearchResults {
43054359
match: String
43064360
}
4307-
4361+
43084362
type Query {
43094363
search(filter: SearchFilter!): [SearchResults!]!
43104364
}`, &queryVarResolver{}, graphql.UseFieldResolvers()),
@@ -4325,11 +4379,11 @@ func TestQueryVariablesValidation(t *testing.T) {
43254379
required: String!
43264380
optional: String
43274381
}
4328-
4382+
43294383
type SearchResults {
43304384
match: String
43314385
}
4332-
4386+
43334387
type Query {
43344388
search(filter: SearchFilter!): [SearchResults!]!
43354389
}`, &queryVarResolver{}, graphql.UseFieldResolvers()),

internal/schema/meta.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ var metaSrc = `
5959
reason: String = "No longer supported"
6060
) on FIELD_DEFINITION | ENUM_VALUE
6161
62+
# Provides a scalar specification URL for specifying the behavior of custom scalar types.
63+
directive @specifiedBy(
64+
# The URL should point to a human-readable specification of the data format, serialization, and coercion rules.
65+
url: String!
66+
) on SCALAR
67+
6268
# A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.
6369
#
6470
# In some cases, you need to provide options to alter GraphQL's execution behavior
@@ -179,6 +185,7 @@ var metaSrc = `
179185
enumValues(includeDeprecated: Boolean = false): [__EnumValue!]
180186
inputFields: [__InputValue!]
181187
ofType: __Type
188+
specifiedByURL: String
182189
}
183190
184191
# An enum describing what kind of type a given ` + "`" + `__Type` + "`" + ` is.

introspection/introspection.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,20 @@ func (r *Type) OfType() *Type {
189189
}
190190
}
191191

192+
func (r *Type) SpecifiedByURL() *string {
193+
switch t := r.typ.(type) {
194+
case *types.ScalarTypeDefinition:
195+
if d := t.Directives.Get("specifiedBy"); d != nil {
196+
arg := d.Arguments.MustGet("url")
197+
url := arg.Deserialize(nil).(string)
198+
return &url
199+
}
200+
default:
201+
return nil
202+
}
203+
return nil
204+
}
205+
192206
type Field struct {
193207
field *types.FieldDefinition
194208
}

0 commit comments

Comments
 (0)