1
1
# GraphQL SOCK
2
2
3
- SOCK: ** Semantic Output Conversion Kit**
3
+ SOCK: ** Semantic Output Conversion Kit** - converting semantic-nullability
4
+ schemas into traditional schemas to support existing tooling (e.g. codegen).
4
5
5
6
## What is it?
6
7
7
8
** Takes as input a GraphQL SDL and outputs a derived SDL wherein all
8
- semantic-non-null type modifiers have either been removed
9
- (` semantic-to-nullable ` ) or have been replaced with strict (traditional)
10
- non-null modifiers (` semantic-to-strict ` ).**
9
+ semantic-non-null type modifiers have either been removed (semantic to nullable)
10
+ or have been replaced with strict (traditional) non-null modifiers (semantic to
11
+ strict).**
12
+
13
+ ### Semantic nullability
11
14
12
15
In the latest proposals around semantic nullability, we introduce a new
13
16
"Semantic Non Null" type modifier that means that the value is "null only on
14
- error". However, not all tools support this yet, so this library contains tools
15
- to convert a modern SDL into a more traditional one, to be used for code
16
- generation and other such functionality.
17
+ error" (i.e. it will never be ` null ` unless an error has occurred). However, not
18
+ all tools support this yet, so this library contains tools to convert a schema
19
+ or SDL that supports semantic nullability into a more traditional one, to be
20
+ used for code generation and other such functionality.
21
+
22
+ Which command you use will depend on your setup; if you're using a client that
23
+ prevents you from reading error nulls (e.g. by throwing when you read from an
24
+ errored field like [ ` graphql-toe ` ] ( https://github.com/graphile/graphql-toe )
25
+ does, or otherwise) then you'll want ` semantic-to-strict ` to really capitalize
26
+ on the benefits of semantic nullability.
27
+
28
+ If you just want to use a semantic nullability SDL with traditional tools and
29
+ clients that don't yet understand semantic nullability, then
30
+ ` semantic-to-nullable ` will just strip out the semantic-non-null types for you.
31
+
32
+ This library supports both the ` @semanticNonNull ` directive (which should work
33
+ universally, but is likely to be a temporary placeholder), and the
34
+ ` GraphQLSemanticNonNull ` wrapper type (if your version of GraphQL.js supports
35
+ it, otherwise it will degrade gracefully to only supporting the directive).
36
+
37
+ ### ` @semanticNonNull ` directive
38
+
39
+ For the directive, the two conversions work like this:
40
+
41
+ | Mode | Input type | Output type |
42
+ | -------------------- | --------------------------------------- | ----------- |
43
+ | semantic-to-nullable | ` Int @semanticNonNull ` | ` Int ` |
44
+ | semantic-to-strict | ` Int @semanticNonNull ` | ` Int! ` |
45
+ | semantic-to-nullable | ` [Int] @semanticNonNull(levels: [1]) ` | ` [Int] ` |
46
+ | semantic-to-strict | ` [Int] @semanticNonNull(levels: [1]) ` | ` [Int!] ` |
47
+ | semantic-to-nullable | ` [Int] @semanticNonNull(levels: [0,1]) ` | ` [Int] ` |
48
+ | semantic-to-strict | ` [Int] @semanticNonNull(levels: [0,1]) ` | ` [Int!]! ` |
49
+
50
+ ### ` GraphQLSemanticNonNull ` wrapper type
51
+
52
+ How the ` GraphQLSemanticNonNull ` type is represented syntactically in SDL is yet
53
+ to be determined by the working group, but this library doesn't care about that
54
+ since it uses the schema directly. For the sake of this README we'll use the
55
+ originally proposed
56
+ [ asterisk syntax] ( https://github.com/graphql/graphql-spec/pull/1065 ) .
57
+
58
+ The above examples using asterisk syntax would be:
17
59
18
- Which command you use will depend on your setup; if you're using ` graphql-toe `
19
- then you'll want ` semantic-to-strict ` to really capitalize on the benefits of
20
- semantic nullability. If you just want to use a semantic nullability SDL with
21
- traditional tools that don't yet understand it, then ` semantic-to-nullable ` will
22
- just strip out the semantic-non-null types for you.
60
+ | Mode | Input type | Output type |
61
+ | -------------------- | ---------- | ----------- |
62
+ | semantic-to-nullable | ` Int* ` | ` Int ` |
63
+ | semantic-to-strict | ` Int* ` | ` Int! ` |
64
+ | semantic-to-nullable | ` [Int*] ` | ` [Int] ` |
65
+ | semantic-to-strict | ` [Int*] ` | ` [Int!] ` |
66
+ | semantic-to-nullable | ` [Int*]* ` | ` [Int] ` |
67
+ | semantic-to-strict | ` [Int*]* ` | ` [Int!]! ` |
23
68
24
69
## Installation
25
70
@@ -33,28 +78,110 @@ pnpm install --save graphql-sock
33
78
34
79
## Usage
35
80
36
- ### ` semantic-to-nullable `
81
+ Consider this "input schema" which uses both the ` @semanticNonNull ` directive
82
+ and the ` * ` syntax (for syntax support, you will need to be running a
83
+ [ compatible version of graphql.js] ( https://github.com/graphql/graphql-js/pull/4192#issuecomment-2351103549 ) ):
84
+
85
+ ### Input schema
86
+
87
+ ``` graphql
88
+ type Query {
89
+ someList : [Int ] @semanticNonNull (levels : [0 , 1 ])
90
+ someOtherList : [String *]*
91
+ }
92
+ ```
93
+
94
+ ### Semantic to nullable
95
+
96
+ **If a value is "null only on error" then it _can_ be null .**
97
+
98
+ This conversion strips all semantic -non -null type wrappers from the SDL , making
99
+ a schema that appears as it traditionally would. This means that you won't reap
100
+ any of the benefits of semantic nullability, but you can support existing tools
101
+ and clients without needing to update their code.
102
+
103
+ #### Output schema
104
+
105
+ The input schema would have all the semantic non-null types removed:
106
+
107
+ ```graphql
108
+ type Query {
109
+ someList : [Int ]
110
+ someOtherList : [String ]
111
+ }
112
+ ```
113
+
114
+ #### CLI
37
115
38
- If a value is "null only on error" then it can be null. This conversion strips
39
- all semantic-non-null type wrappers from the SDL, making a schema that appears
40
- as it traditionally would. This means that you won't reap any of the benefits of
41
- semantic nullability, but you can support existing tools.
116
+ From the CLI, use the ` semantic-to-nullable ` command to convert an SDL with
117
+ semantic nullability into an SDL without semantic nullability, where all
118
+ semantic non-null positions have been removed:
42
119
43
120
```
44
121
semantic-to-nullable -i input.graphql -o output.graphql
45
122
```
46
123
47
- ### ` semantic-to-strict `
124
+ #### Library
125
+
126
+ Use the ` semanticToNullable ` export to create a copy of a schema with all the
127
+ semantic non-null types removed:
128
+
129
+ ``` ts
130
+ import { semanticToNullable } from " graphql-sock" ;
131
+ import { sourceSchema as inputSchema } from " ./my-schema" ;
132
+
133
+ export const outputSchema = semanticToNullable (inputSchema );
134
+ ```
135
+
136
+ ### Semantic to strict
137
+
138
+ ** Error handling clients prevent users from reading "error-nulls" (e.g. by
139
+ throwing an error), so semantically non-nullable positions are non-nullable for
140
+ these clients.**
141
+
142
+ If you're using "Throw On Error" (e.g. via
143
+ [ graphql-toe] ( https://github.com/graphile/graphql-toe ) ) or a similar technique
144
+ then when you read from an errored field an error will be thrown, preventing you
145
+ from reading the underlying ` null ` .
146
+
147
+ ** Think of semantically non-null fields as "null only on error;" if you throw on
148
+ errors, then they're never null!**
149
+
150
+ As such, this position becomes equivalent to a traditional non-null for you, so
151
+ this conversion converts all semantic-non-null type wrappers into traditional
152
+ (strict) non-null wrappers. Your type generators can therefore generate fewer
153
+ nullables, and your frontend engineers have to do fewer null checks and are
154
+ therefore happier.
155
+
156
+ #### Output schema
157
+
158
+ The input schema would become:
159
+
160
+ ``` graphql
161
+ type Query {
162
+ someList : [Int ! ]!
163
+ someOtherList : [String ! ]!
164
+ }
165
+ ```
166
+
167
+ #### CLI
48
168
49
- If you're using [ graphql-toe] ( https://github.com/graphile/graphql-toe ) or a
50
- similar technique that means that when you read from an errored field the error
51
- will be thrown, then it will not be possible for you to read a ` null ` from a
52
- "null only on error" position. As such, this position becomes equivalent to a
53
- traditional non-null for you, so this conversion converts all semantic-non-null
54
- type wrappers into traditional non-null wrappers. Your type generators can
55
- therefore generate fewer nullables, and your frontend engineers have to do fewer
56
- null checks and are therefore happier.
169
+ From the CLI , use the `semantic -to -strict ` command to convert an SDL with
170
+ semantic nullability into an SDL without semantic nullability , where all
171
+ semantic non -null positions have become strictly non -null :
57
172
58
173
```
59
174
semantic-to-strict -i input.graphql -o output.graphql
60
175
```
176
+
177
+ #### Library
178
+
179
+ Use the `semanticToStrict` export to create a copy of a schema with all the
180
+ semantic non-null types replaced with strict (traditional) non-null types:
181
+
182
+ ```ts
183
+ import { semanticToStrict } from "graphql-sock";
184
+ import { schema as sourceSchema } from "./my-schema";
185
+
186
+ export const schema = semanticToStrict(sourceSchema);
187
+ ```
0 commit comments