-
Notifications
You must be signed in to change notification settings - Fork 4
Persisted documents snippet. #54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 4 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
# Persisted Documents | ||
|
||
GraphQL _executable documents_ containing at least one operation definition | ||
and optional fragment defintions can be persisted with a schema. | ||
|
||
## Overview | ||
|
||
The optional `executables` argument of `@sdl` takes a list of input document files | ||
that are GraphQL _executable documents_. | ||
|
||
``` | ||
@sdl( | ||
files: [] | ||
executables: [{ document: "operations.graphql", persist: true }] | ||
) | ||
``` | ||
|
||
When a schema is deployed the _executable documents_ must validate successfully | ||
against the schema. | ||
|
||
By itself this can be used to validate applications' use | ||
of a GraphQL endpoint remain valid when the schema changes. | ||
This requires that the application loads GraphQL requests from | ||
files containing executable documents that are declared in the schema. | ||
|
||
In addition any _executable document_ in the schema that is marked with `persist: true` | ||
is loaded as a _persisted document_. | ||
|
||
A client uses a _persisted document_ by specifying its document identifier | ||
(based upon a SHA256 hash) in a request instead of the content of the _executable document_. | ||
|
||
For example instead of this POST body for a request: | ||
|
||
``` | ||
{ | ||
"query": "{__typname}" | ||
} | ||
``` | ||
|
||
a request can use this: | ||
|
||
``` | ||
{ | ||
"documentId": "sha256:ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38" | ||
} | ||
``` | ||
|
||
if an _executable document_ was declared in the schema with the matching SHA256 hash. | ||
|
||
The request parameters `operationName` and `variables` can be used as required with `documentId`. | ||
|
||
## Benefits | ||
|
||
Use of persisted documents typically saves network bandwidth as for real application requests | ||
the hash is smaller than the body of the _executable document_. | ||
|
||
In addition query requests can use HTTP GET while maintaining a reasonable sized URL | ||
that improves caching of URL requests. For example the above request can be a coded as an HTTP GET: | ||
|
||
``` | ||
https://london.us-east-a.ibm.stepzen.net/api/customer/graphql?documentId=sha256%3Aecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38 | ||
``` | ||
|
||
## Executable Documents | ||
|
||
A good practice is to ensure that a CI/CD process ensures that _executable documents_ declared as | ||
part of the schema using `@sdl(executables:)` are formatted consistentcy, using tooling such as `prettier`. | ||
|
||
For example the simple _executable document_ shown above `{__typename}` stored in a document file | ||
and formatted will have contents (including a newline at the end): | ||
|
||
``` | ||
{ | ||
__typename | ||
} | ||
``` | ||
|
||
and thus a document identifier of `sha256:8d8f7365e9e86fa8e3313fcaf2131b801eafe9549de22373089cf27511858b39`. | ||
|
||
Clients can obtain the SHA256 hash for a document identifer using any standard mechanism for calculating hashes, | ||
for example on Linux/Unix systems this command can be used: | ||
|
||
``` | ||
shasum -a 256 operations.graphql | ||
``` | ||
|
||
When _executable documents_ are persisted using `@sdl(executables:)` the schema calculates the document identifiers automatically. | ||
|
||
## Example | ||
|
||
This example uses a simple mocked schema with a `Customer` type and a single `Query` field `customer`. | ||
|
||
`operations.graphql` contains three GraphQL query operations `Customer`, `CustomerEmail` and `CustomerName` | ||
each with a different selection against `Query.customer`. | ||
|
||
A client can execute them using these request parameters, shown as JavaScript: | ||
|
||
``` | ||
{ | ||
documentId: "sha256:9d50d8e35b5882139e836a126f5d6d5a28cf41c5efd80a6e67f920d284b5f6d0", | ||
operationName: "Customer", | ||
variables: { | ||
id: 1789, | ||
}, | ||
} | ||
``` | ||
|
||
``` | ||
{ | ||
documentId: "sha256:9d50d8e35b5882139e836a126f5d6d5a28cf41c5efd80a6e67f920d284b5f6d0", | ||
operationName: "CustomerEmail", | ||
variables: { | ||
id: 2845, | ||
}, | ||
} | ||
``` | ||
|
||
``` | ||
{ | ||
documentId: "sha256:9d50d8e35b5882139e836a126f5d6d5a28cf41c5efd80a6e67f920d284b5f6d0", | ||
operationName: "CustomerName", | ||
variables: { | ||
id: 3651, | ||
}, | ||
} | ||
``` | ||
|
||
For example use `curl` and HTTP `GET` as follows: | ||
|
||
``` | ||
curl \ | ||
--header "Authorization: Apikey $(stepzen whoami --apikey)" \ | ||
--header "Content-Type: application/json" \ | ||
'https://london.us-east-a.ibm.stepzen.net/api/miscellaneous/graphql?documentId=sha256:9d50d8e35b5882139e836a126f5d6d5a28cf41c5efd80a6e67f920d284b5f6d0&operationName=Customer&variables=%7B%22id%22%3A%201789%7D' | ||
``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
schema | ||
@sdl( | ||
files: [] | ||
# executables defines a list of GraphQL executable documents that | ||
# are validated against the schema when deployed. | ||
# If an executable document is marked as persist: true | ||
# then it becomes a persisted document with the document identifier | ||
# being tha SHA 256 hash of the document file. | ||
executables: [{ document: "operations.graphql", persist: true }] | ||
) { | ||
query: Query | ||
} | ||
|
||
type Query { | ||
customer(id: ID!): Customer | ||
} | ||
type Customer @mock { | ||
id: ID! | ||
name: String! @mockfn(name: "LastName") | ||
email: String @mockfn(name: "Email") | ||
phone: String @mockfn(name: "Phone") | ||
address: Address | ||
} | ||
type Address { | ||
city: String @mockfn(name: "City") | ||
zip: String @mockfn(name: "Zip") | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
query Customer($id: ID!) { | ||
customer(id: $id) { | ||
id | ||
name | ||
phone | ||
address { | ||
city | ||
zip | ||
} | ||
} | ||
} | ||
|
||
query CustomerName($id: ID!) { | ||
customer(id: $id) { | ||
name | ||
} | ||
} | ||
|
||
query CustomerEmail($id: ID!) { | ||
customer(id: $id) { | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"endpoint": "api/miscellaneous" | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
const fs = require("fs"); | ||
const path = require("node:path"); | ||
|
||
const { | ||
deployAndRun, | ||
authTypes, | ||
getTestDescription, | ||
} = require("../../../tests/gqltest.js"); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there any way to define the REPO_ROOT like we have done in our Makefiles? this |
||
testDescription = getTestDescription("snippets", __dirname); | ||
|
||
const requestsFile = path.join(path.dirname(__dirname), "operations.graphql"); | ||
const requests = fs.readFileSync(requestsFile, "utf8").toString(); | ||
|
||
describe(testDescription, function () { | ||
const tests = [ | ||
{ | ||
label: "CustomerName", | ||
documentId: | ||
"sha256:9d50d8e35b5882139e836a126f5d6d5a28cf41c5efd80a6e67f920d284b5f6d0", | ||
operationName: "CustomerName", | ||
variables: { | ||
id: 1031, | ||
}, | ||
expected: { | ||
customer: { | ||
name: "Tromp", | ||
}, | ||
}, | ||
authType: authTypes.adminKey, | ||
}, | ||
{ | ||
label: "CustomerName", | ||
documentId: | ||
"sha256:9d50d8e35b5882139e836a126f5d6d5a28cf41c5efd80a6e67f920d284b5f6d0", | ||
operationName: "CustomerEmail", | ||
variables: { | ||
id: 2845, | ||
}, | ||
expected: { | ||
customer: { | ||
email: "[email protected]", | ||
}, | ||
}, | ||
authType: authTypes.adminKey, | ||
}, | ||
{ | ||
label: "Customer", | ||
documentId: | ||
"sha256:9d50d8e35b5882139e836a126f5d6d5a28cf41c5efd80a6e67f920d284b5f6d0", | ||
operationName: "Customer", | ||
variables: { | ||
id: 3293, | ||
}, | ||
expected: { | ||
customer: { | ||
id: "3293", | ||
name: "Veum", | ||
email: null, | ||
phone: "5349179326", | ||
address: { | ||
city: "New Abshire", | ||
zip: "75624", | ||
}, | ||
}, | ||
}, | ||
authType: authTypes.adminKey, | ||
}, | ||
]; | ||
return deployAndRun(__dirname, tests); | ||
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.