@@ -32,6 +32,51 @@ thus should generate different document identifiers.
32
32
A _ document identifier_ must either be a _ prefixed document identifier_ or a
33
33
_ custom document identifier_ .
34
34
35
+ A _ document identifier_ must only contain colons (` : ` ) and characters that are
36
+ defined as
37
+ [ ` unreserved ` in RFC3986] ( https://datatracker.ietf.org/doc/html/rfc3986#section-2.3 )
38
+ (alphanumeric characters (` A-Z ` , ` a-z ` , ` 0-9 ` ), dashes (` - ` ), periods (` . ` ),
39
+ underscores (` _ ` ), and tildes (` ~ ` )).
40
+
41
+ DocumentIdentifier ::
42
+
43
+ - PrefixedDocumentIdentifier
44
+ - CustomDocumentIdentifier
45
+
46
+ PrefixedDocumentIdentifier ::
47
+
48
+ - UnreservedCharacter+ PrefixedDocumentIdentifierContinue+
49
+
50
+ PrefixedDocumentIdentifierContinue ::
51
+
52
+ - Colon UnreservedCharacter\*
53
+
54
+ CustomDocumentIdentifier ::
55
+
56
+ - UnreservedCharacter+ [ lookahead != Colon]
57
+
58
+ UnreservedCharacter ::
59
+
60
+ - Letter
61
+ - Digit
62
+ - ` - `
63
+ - ` . `
64
+ - ` _ `
65
+ - ` ~ `
66
+
67
+ Letter :: one of
68
+
69
+ - ` A ` ` B ` ` C ` ` D ` ` E ` ` F ` ` G ` ` H ` ` I ` ` J ` ` K ` ` L ` ` M `
70
+ - ` N ` ` O ` ` P ` ` Q ` ` R ` ` S ` ` T ` ` U ` ` V ` ` W ` ` X ` ` Y ` ` Z `
71
+ - ` a ` ` b ` ` c ` ` d ` ` e ` ` f ` ` g ` ` h ` ` i ` ` j ` ` k ` ` l ` ` m `
72
+ - ` n ` ` o ` ` p ` ` q ` ` r ` ` s ` ` t ` ` u ` ` v ` ` w ` ` x ` ` y ` ` z `
73
+
74
+ Digit :: one of
75
+
76
+ - ` 0 ` ` 1 ` ` 2 ` ` 3 ` ` 4 ` ` 5 ` ` 6 ` ` 7 ` ` 8 ` ` 9 `
77
+
78
+ Colon :: ` : `
79
+
35
80
### Prefixed Document Identifier
36
81
37
82
:: A _ prefixed document identifier_ is a document identifier that contains at
@@ -86,14 +131,46 @@ Would have this different _SHA256 hex document identifier_:
86
131
sha256:71f7dc5758652baac68e4a10c50be732b741c892ade2883a99358f52b555286b
87
132
```
88
133
134
+ Persisted Documents may contain multiple (named) operations and fragments too;
135
+ so the following GraphQL document (with no trailing newline):
136
+
137
+ ``` graphql example
138
+ query UserName ($id : ID ! ) {
139
+ user (id : $id ) {
140
+ name
141
+ }
142
+ }
143
+
144
+ query FriendsNames ($id : ID ! ) {
145
+ user (id : $id ) {
146
+ ... User
147
+ friends {
148
+ ... User
149
+ }
150
+ }
151
+ }
152
+
153
+ fragment User on User {
154
+ id
155
+ name
156
+ }
157
+ ```
158
+
159
+ Would have the following _ SHA256 hex document identifier_ :
160
+
161
+ ``` example
162
+ sha256:517c56d2ba0779653b7698881207f749509f331bdaccbe951a82c378bc869556
163
+ ```
164
+
89
165
### Custom Document Identifier
90
166
91
167
:: A _ custom document identifier_ is a document identifier that contains no
92
168
colon symbols (` : ` ). The meaning of a custom document identifier is
93
169
implementation specific.
94
170
95
- Note: A 32 character hexadecimal _ custom document identifier_ is likely to be an
96
- MD5 hash of the GraphQL document, as traditionally used by Relay.
171
+ Note: A 32 character hexadecimal lower-case _ custom document identifier_ is
172
+ likely to be an MD5 hash of the GraphQL document, as traditionally used by
173
+ Relay.
97
174
98
175
## Persisting a Document
99
176
@@ -105,12 +182,11 @@ specific.
105
182
106
183
Note: When used as an operation allow-list, persisted documents are typically
107
184
stored into a trusted shared key-value store at client build time (either
108
- directly, or indirectly via an authenticated request to the server) such that
109
- the server may retrieve them given the identifier at request time. This must be
110
- done in a secure manner (preventing untrusted third parties from adding their
111
- own persisted document) such that the server will be able to retrieve the
112
- identified document within a _ persisted document request_ and know that it is
113
- trusted.
185
+ directly, or indirectly via authenticated requests to the server) such that the
186
+ server may retrieve them given the identifier at request time. This must be done
187
+ in a secure manner (preventing untrusted third parties from adding their own
188
+ persisted document) such that the server will be able to retrieve the identified
189
+ document within a _ persisted document request_ and know that it is trusted.
114
190
115
191
Note: When used solely as a bandwidth optimization, as in the technique known
116
192
colloquially as "automatic persisted queries (APQ)," an error-based mechanism
@@ -130,12 +206,16 @@ deployed client.
130
206
131
207
## Persisted Document Request
132
208
133
- A server MAY accept a _ persisted document request_ via ` GET ` or ` POST ` .
209
+ A server MAY accept a _ persisted document request_ via an HTTP ` GET ` or ` POST `
210
+ request to a _ GraphQL endpoint_ or subpath thereof.
134
211
135
212
### Persisted Document Request Parameters
136
213
137
- :: A _ persisted document request_ is an HTTP request that encodes the following
138
- parameters in one of the manners described in this specification:
214
+ :: A _ persisted document request_ is an HTTP request that encodes the _ persisted
215
+ document request parameters_ in one of the manners described in this
216
+ specification.
217
+
218
+ :: The _ persisted document request parameters_ are as follows:
139
219
140
220
- {documentId} - (_ Required_ , string): The string identifier for the Document.
141
221
- {operationName} - (_ Optional_ , string): The name of the Operation in the
@@ -145,20 +225,62 @@ parameters in one of the manners described in this specification:
145
225
- {extensions} - (_ Optional_ , map): This entry is reserved for implementors to
146
226
extend the protocol however they see fit.
147
227
228
+ ### Persisted Document Request URL
229
+
230
+ To enable non-GraphQL HTTP tooling to better integrate with a Persisted Document
231
+ Request, it is recommended that the URL to which a Persisted Document Request is
232
+ sent is a subpath of the _ GraphQL endpoint_ containing the {documentId} and the
233
+ {operationName} (if any) separated by a forward slash character (` / ` ). It is
234
+ recommended that this practice is only followed when {documentId} is a prefixed
235
+ document identifier, since the prefix helps avoid clashes with other subpaths of
236
+ the _ GraphQL endpoint_ .
237
+
238
+ Note: By following this practice, traditional HTTP tooling can exercise concerns
239
+ such as caching, rate limiting, audit logging, access-pattern analysis, error
240
+ detection, monitoring and more without needing to fully parse the incoming
241
+ GraphQL request.
242
+
243
+ For example, if the _ GraphQL endpoint_ is ` https://example.com/graphql ` then a
244
+ persisted document request may be made to an endpoint such as
245
+ ` https://example.com/graphql/sha256:517c56d2ba0779653b7698881207f749509f331bdaccbe951a82c378bc869556/FriendNames ` .
246
+ For documents containing a single anonymous operation the final segment must be
247
+ omitted, e.g.
248
+ ` https://example.com/graphql/sha256:71f7dc5758652baac68e4a10c50be732b741c892ade2883a99358f52b555286b ` .
249
+
250
+ Legacy persisted document implementations often issue requests to the _ GraphQL
251
+ endpoint_ directly (i.e. without a subpath), so it's recommended to support this
252
+ pattern too.
253
+
254
+ :: The term _ remaining parameters_ refers to the _ persisted document request
255
+ parameters_ that are not encoded via the URL subpath; i.e. when the GraphQL
256
+ endpoint is queried directly the remaining request parameters are {documentId},
257
+ {operationName}, {variables} and {extensions}, whereas when the subpath
258
+ technique described above is used the remaining parameters are {variables} and
259
+ {extensions}.
260
+
148
261
### GET
149
262
150
- For a _ persisted document request_ using HTTP GET, parameters SHOULD be provided
151
- in the query component of the request URL, encoded in the
263
+ For a _ persisted document request_ using HTTP GET, the _ remaining parameters _
264
+ SHOULD be provided in the query component of the request URL, encoded in the
152
265
` application/x-www-form-urlencoded ` format as specified by the
153
266
[ WhatWG URLSearchParams class] ( https://url.spec.whatwg.org/#interface-urlsearchparams ) .
154
267
268
+ Note: This is only a SHOULD recommendation to allow for variables which are too
269
+ long for the query component to be encoded in an alternative way, for example
270
+ via headers.
271
+
155
272
The {documentId} parameter must be a string _ document identifier_ .
156
273
157
274
The {operationName} parameter, if present, must be a string.
158
275
159
276
Each of the {variables} and {extensions} parameters, if used, MUST be encoded as
160
277
a JSON string.
161
278
279
+ Note: JSON encoding is used here to enable reliable encoding of custom scalars
280
+ and composite/list inputs; traditional HTTP query strings do not encode enough
281
+ detail to tell the difference between a boolean ` true ` and the string ` "true" ` ,
282
+ for example.
283
+
162
284
Setting the value of the {operationName} parameter to the empty string is
163
285
equivalent to omitting the {operationName} parameter.
164
286
0 commit comments