Skip to content

feat: perform function that does parsing, validation, context assembly and execution/subscription #1515

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

Open
wants to merge 65 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 51 commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
726519d
feat: non-breaking GraphQL Engine
saihaj Aug 17, 2022
a84ea46
feat: make envelop take in engine functions
saihaj Aug 22, 2022
5320ae5
structural typings
saihaj Aug 22, 2022
871208e
remove grapqhl as peer dep from types pkg
saihaj Aug 22, 2022
732ec5e
make core more agnostic
saihaj Aug 22, 2022
4d09e1d
chore(dependencies): updated changesets for modified dependencies
github-actions[bot] Aug 22, 2022
4f6fe63
remove traced schema
saihaj Aug 23, 2022
dd616a1
remove traced orchestrator
saihaj Aug 23, 2022
1244549
make plugin agnostic
saihaj Aug 23, 2022
28bfd92
drop EnvelopError
saihaj Aug 23, 2022
6ba3999
remove more graphql import
saihaj Aug 23, 2022
ae21a6e
Drop useTiming
saihaj Aug 23, 2022
da7c81c
make core completely free of graphql-js
saihaj Aug 23, 2022
5010b96
add eslint rule
saihaj Aug 23, 2022
2f8c24b
eslint disallow in types too
saihaj Aug 23, 2022
d55b626
more agnostic packages
saihaj Aug 23, 2022
184db16
remove introspection util
saihaj Aug 24, 2022
06687c4
Merge branch 'main' into saihaj/engine-agnostic-non-breaking
saihaj Aug 24, 2022
6964702
chore(dependencies): updated changesets for modified dependencies
github-actions[bot] Aug 24, 2022
6ec5792
prettier
saihaj Aug 24, 2022
680dbda
TEMP: make bot calm down
saihaj Aug 24, 2022
f0373e1
update all docs
saihaj Aug 24, 2022
d8be662
test matrix for core
saihaj Aug 24, 2022
c1274cd
experimenting traced schema (#1501)
saihaj Aug 31, 2022
2647f7f
feat: drop node 12 (#1505)
saihaj Sep 1, 2022
3442989
Merge branch 'main' into saihaj/engine-agnostic-non-breaking
saihaj Sep 1, 2022
5ab6cc6
feat: remove `enableIf` utility (#1504)
saihaj Sep 2, 2022
6e27fdd
feat: remove async schema plugin and rename lazy loaded schema plugin…
saihaj Sep 5, 2022
59d8a78
add eslint rule (#1509)
saihaj Sep 7, 2022
49cf420
feat: `@envelop/on-resolve` plugin for hooking into schema resolvers …
enisdenjo Sep 7, 2022
050d317
docs: order of plugins matter (#1513)
saihaj Sep 7, 2022
b1bf2e9
feat: remove handler for validation and parse errors (#1510)
saihaj Sep 8, 2022
503846a
begin
enisdenjo Sep 9, 2022
19cd80c
organize imports
enisdenjo Sep 9, 2022
823b318
support subscriptions
enisdenjo Sep 9, 2022
8b3de5e
with context extension
enisdenjo Sep 9, 2022
dbfb294
should include parsing and validation errors in result
enisdenjo Sep 9, 2022
63929b1
on perform plugin
enisdenjo Sep 9, 2022
cba0e69
test replacing params and result
enisdenjo Sep 9, 2022
2e2127f
early result
enisdenjo Sep 9, 2022
d072fe3
refactor and invoke onDone always
enisdenjo Sep 9, 2022
b052f60
changeset
enisdenjo Sep 9, 2022
7b7b530
add changeset
saihaj Sep 12, 2022
593b119
Merge branch 'main' into saihaj/engine-agnostic-non-breaking
saihaj Sep 12, 2022
cdbfbb2
Update .changeset/nervous-seas-own.md
saihaj Sep 12, 2022
ebf9e1a
Update .changeset/rude-cats-peel.md
saihaj Sep 12, 2022
7bc6412
no-use-before-define (#1522)
enisdenjo Sep 13, 2022
e923bce
document and recommend perform
enisdenjo Sep 13, 2022
b87758d
comment on perform func
enisdenjo Sep 13, 2022
9a59c62
perform query param can be a graphql document
enisdenjo Sep 13, 2022
827fb17
update apollo-server example
enisdenjo Sep 13, 2022
1770063
feat: trigger on context, validate and parse errors (#1511)
saihaj Sep 13, 2022
3dcdd03
Revert "perform query param can be a graphql document"
enisdenjo Sep 14, 2022
cdb23b5
drop unused import
enisdenjo Sep 14, 2022
d542d3e
perform params query is optional (persisted queries)
enisdenjo Sep 14, 2022
3ccdd02
perform takes apollo-server request
enisdenjo Sep 14, 2022
40f760e
revert apollo-server example
enisdenjo Sep 14, 2022
2e2209b
perform should catch thrown validation errors too
enisdenjo Sep 14, 2022
0dd0915
context factory after parse and validate
enisdenjo Sep 14, 2022
3b098bf
perform in testkit
enisdenjo Sep 14, 2022
288fd29
tests use perform
enisdenjo Sep 15, 2022
7cab2a3
only GraphQL errors are a part of the result
enisdenjo Sep 15, 2022
9399a33
docs: migration guide (#1520)
saihaj Sep 15, 2022
1720176
Add redirects
saihaj Sep 15, 2022
01669df
Merge branch 'saihaj/engine-agnostic-non-breaking' into perform
enisdenjo Sep 15, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/@envelop_apollo-tracing-1487-dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@envelop/apollo-tracing': patch
---

dependencies updates:

- Added dependency [`@envelop/types@^2.3.1` ↗︎](https://www.npmjs.com/package/@envelop/types/v/null) (to `peerDependencies`)
7 changes: 7 additions & 0 deletions .changeset/@envelop_auth0-1487-dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@envelop/auth0': patch
---

dependencies updates:

- Removed dependency [`graphql@^14.0.0 || ^15.0.0 || ^16.0.0` ↗︎](https://www.npmjs.com/package/graphql/v/null) (from `peerDependencies`)
7 changes: 7 additions & 0 deletions .changeset/@envelop_core-1487-dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@envelop/core': patch
---

dependencies updates:

- Removed dependency [`graphql@^14.0.0 || ^15.0.0 || ^16.0.0` ↗︎](https://www.npmjs.com/package/graphql/v/null) (from `peerDependencies`)
7 changes: 7 additions & 0 deletions .changeset/@envelop_dataloader-1487-dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@envelop/dataloader': patch
---

dependencies updates:

- Removed dependency [`graphql@^14.0.0 || ^15.0.0 || ^16.0.0` ↗︎](https://www.npmjs.com/package/graphql/v/null) (from `peerDependencies`)
7 changes: 7 additions & 0 deletions .changeset/@envelop_opentelemetry-1487-dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@envelop/opentelemetry': patch
---

dependencies updates:

- Added dependency [`@envelop/types@^2.3.1` ↗︎](https://www.npmjs.com/package/@envelop/types/v/null) (to `peerDependencies`)
7 changes: 7 additions & 0 deletions .changeset/@envelop_preload-assets-1487-dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@envelop/preload-assets': patch
---

dependencies updates:

- Removed dependency [`graphql@^14.0.0 || ^15.0.0 || ^16.0.0` ↗︎](https://www.npmjs.com/package/graphql/v/null) (from `peerDependencies`)
7 changes: 7 additions & 0 deletions .changeset/@envelop_prometheus-1487-dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@envelop/prometheus': patch
---

dependencies updates:

- Added dependency [`@envelop/types@^2.3.1` ↗︎](https://www.npmjs.com/package/@envelop/types/v/null) (to `peerDependencies`)
7 changes: 7 additions & 0 deletions .changeset/@envelop_rate-limiter-1487-dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@envelop/rate-limiter': patch
---

dependencies updates:

- Added dependency [`@envelop/types@^2.3.1` ↗︎](https://www.npmjs.com/package/@envelop/types/v/null) (to `peerDependencies`)
7 changes: 7 additions & 0 deletions .changeset/@envelop_statsd-1487-dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@envelop/statsd': patch
---

dependencies updates:

- Removed dependency [`graphql@^14.0.0 || ^15.0.0 || ^16.0.0` ↗︎](https://www.npmjs.com/package/graphql/v/null) (from `peerDependencies`)
7 changes: 7 additions & 0 deletions .changeset/@envelop_types-1487-dependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@envelop/types': patch
---

dependencies updates:

- Removed dependency [`graphql@^14.0.0 || ^15.0.0 || ^16.0.0` ↗︎](https://www.npmjs.com/package/graphql/v/null) (from `peerDependencies`)
5 changes: 5 additions & 0 deletions .changeset/curvy-bottles-repeat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@envelop/core': major
---

Remove async schema loading plugin. This was a mistake from beginning as we cannot asynchronously `validate` and `parse` since with GraphQL.js are synchronous in nature.
5 changes: 5 additions & 0 deletions .changeset/four-masks-jam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@envelop/core': minor
---

`perform` function that does parsing, validation, context assembly and execution/subscription
5 changes: 5 additions & 0 deletions .changeset/neat-spoons-play.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@envelop/on-resolve': major
---

Plugin allowing you to hook into resolves of every field in the GraphQL schema.
5 changes: 5 additions & 0 deletions .changeset/nervous-seas-own.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@envelop/core': major
---

Renmae `useLazyLoadedSchema` to `useSchemaByContext` since the original name was vert misleading.
27 changes: 27 additions & 0 deletions .changeset/quiet-mice-jam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
'@envelop/core': major
---

Remove `enableIf` utility in favor of more type safe way to conditionally enable plugins. It wasn't a great experience to have a utility

We can easily replace usage like this:

```diff
- import { envelop, useMaskedErrors, enableIf } from '@envelop/core'
+ import { envelop, useMaskedErrors } from '@envelop/core'
import { parse, validate, execute, subscribe } from 'graphql'

const isProd = process.env.NODE_ENV === 'production'

const getEnveloped = envelop({
parse,
validate,
execute,
subscribe,
plugins: [
// This plugin is enabled only in production
- enableIf(isProd, useMaskedErrors())
+ isProd && useMaskedErrors()
]
})
```
10 changes: 10 additions & 0 deletions .changeset/rude-cats-peel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@envelop/core': major
---

Remove `handleValidationErrors` and `handleParseErrors` options from `useMaskedErrors`.

> ONLY masking validation errors OR ONLY disabling introspection errors does not make sense, as both can be abused for reverse-engineering the GraphQL schema (see https://github.com/nikitastupin/clairvoyance for reverse-engineering the schema based on validation error suggestions).
> https://github.com/n1ru4l/envelop/issues/1482#issue-1340015060

Rename `formatError` function option to `maskErrorFn`
60 changes: 55 additions & 5 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
{
"parser": "@typescript-eslint/parser",
"extends": ["eslint:recommended", "standard", "prettier", "plugin:@typescript-eslint/recommended"],
"plugins": ["@typescript-eslint", "unicorn"],
"extends": [
"eslint:recommended",
"standard",
"prettier",
"plugin:@typescript-eslint/recommended",
"plugin:package-json/recommended"
],
"plugins": ["@typescript-eslint", "unicorn", "package-json"],
"rules": {
"unicorn/filename-case": "error",
"no-lonely-if": "error",
"unicorn/no-lonely-if": "error",
"no-empty": "off",
"no-console": "error",
"no-prototype-builtins": "off",
"prefer-arrow-callback": ["error", { "allowNamedFunctions": true }],
"prefer-arrow-callback": [
"error",
{
"allowNamedFunctions": true
}
],
"no-useless-constructor": "off",
"@typescript-eslint/no-unused-vars": ["warn", { "args": "none" }],
"@typescript-eslint/no-unused-vars": [
"warn",
{
"args": "none"
}
],
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/no-namespace": "off",
"@typescript-eslint/no-empty-interface": "off",
Expand All @@ -26,7 +42,9 @@
"unicorn/no-useless-fallback-in-spread": "error",
"import/no-extraneous-dependencies": [
"error",
{ "devDependencies": ["**/*.test.ts", "**/*.spec.ts", "**/test/**/*.ts"] }
{
"devDependencies": ["**/*.test.ts", "**/*.spec.ts", "**/test/**/*.ts"]
}
]
},
"env": {
Expand All @@ -43,6 +61,38 @@
"@typescript-eslint/no-unused-vars": "off",
"import/no-extraneous-dependencies": "off"
}
},
// Disallow `graphql-js` specific things to get re-introduced in agnostic packages.
{
"files": [
"packages/core/**",
"packages/types/**",
"packages/plugins/apollo-datasources/**",
"packages/plugins/auth0/**",
"packages/plugins/dataloader/**",
"packages/plugins/preload-assets/**",
"packages/plugins/statsd/**"
],
"env": {
"jest": true
},
"rules": {
"no-restricted-imports": [
"error",
{
"paths": [
{
"name": "graphql",
"message": "You chose violence. Try to make it work without using GraphQL.js"
},
{
"name": "@graphql-tools/*",
"message": "You chose violence. Try to make it work without using `graphql-tools`"
}
]
}
]
}
}
],
"ignorePatterns": ["dist", "node_modules", "dev-test", "website"]
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ on:
- main

jobs:
dependencies:
uses: the-guild-org/shared-config/.github/workflows/changesets-dependencies.yaml@main
secrets:
githubToken: ${{ secrets.GITHUB_TOKEN }}
# dependencies:
# uses: the-guild-org/shared-config/.github/workflows/changesets-dependencies.yaml@main
# secrets:
# githubToken: ${{ secrets.GITHUB_TOKEN }}

release:
uses: the-guild-org/shared-config/.github/workflows/release-snapshot.yml@main
Expand Down
35 changes: 30 additions & 5 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,38 @@ jobs:
run: yarn ts:check

unit:
name: unit / ${{matrix.os}} / node v${{matrix.node-version}} / graphql v${{matrix.graphql_version}}
name: Unit Test
runs-on: ${{matrix.os}}
strategy:
matrix:
os: [ubuntu-latest] # remove windows to speed up the tests
node-version: [12, 17]
graphql_version: [15, 16]
steps:
- name: Checkout Master
uses: actions/checkout@v2
- name: Setup env
uses: the-guild-org/shared-config/setup@main
with:
nodeVersion: 18
- name: Install Dependencies
run: yarn install --ignore-engines && git checkout yarn.lock
- name: Cache Jest
uses: actions/cache@v2
with:
path: .cache/jest
key: ${{ runner.os }}-${{matrix.node-version}}-${{matrix.graphql_version}}-jest-${{ hashFiles('yarn.lock') }}-${{ hashFiles('patches/*.patch') }}
- name: Test
run: yarn test
env:
CI: true

core:
name: Core Test / ${{matrix.os}} / node v${{matrix.node-version}} / graphql v${{matrix.graphql_version}}
runs-on: ${{matrix.os}}
strategy:
matrix:
os: [ubuntu-latest] # remove windows to speed up the tests
node-version: [14, 16, 17, 18]
graphql_version: [15, 16, 'npm:@graphql-tools/graphql@0.1.0-alpha-20220815193214-83898018']
steps:
- name: Checkout Master
uses: actions/checkout@v2
Expand All @@ -71,8 +96,8 @@ jobs:
with:
path: .cache/jest
key: ${{ runner.os }}-${{matrix.node-version}}-${{matrix.graphql_version}}-jest-${{ hashFiles('yarn.lock') }}-${{ hashFiles('patches/*.patch') }}
- name: Test
run: yarn test --ci
- name: Test Core
run: yarn test:core --ci
env:
CI: true

Expand Down
22 changes: 5 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,33 +46,21 @@ const getEnveloped = envelop({
})
```

The result of `envelop` is a function that allows you to get everything you need for the GraphQL execution: `parse`, `validate`, `contextBuilder` and `execute`. Use that to run the client's GraphQL queries. Here's a pseudo-code example of how it should look like:
The result of `envelop` is a function that allows you to get everything you need for the GraphQL execution. It's recommended to use the `perform` function which does parsing, validation, context assembly and execution/subscription, and returns a ready result. Here's a pseudo-code example of how it should look like:

```ts
const httpServer = createServer()

httpServer.on('request', async (req, res) => {
// Here you get the alternative methods that are bundled with your plugins
// You can also pass the "req" to make it available for your plugins or GraphQL context.
const { parse, validate, contextFactory, execute, schema } = getEnveloped({ req })
const { perform } = getEnveloped({ req })

// Parse the initial request and validate it
// Parse the initial request
const { query, variables } = JSON.parse(req.payload)
const document = parse(query)
const validationErrors = validate(schema, document)

if (validationErrors.length > 0) {
return res.end(JSON.stringify({ errors: validationErrors }))
}

// Build the context and execute
const context = await contextFactory(req)
const result = await execute({
document,
schema,
variableValues: variables,
contextValue: context
})
// Perform the GraphQL operation
const result = await perform({ query, variables })

// Send the response
res.end(JSON.stringify(result))
Expand Down
22 changes: 2 additions & 20 deletions examples/simple-http/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const getEnveloped = envelop({
});

const server = createServer((req, res) => {
const { parse, validate, contextFactory, execute, schema } = getEnveloped({ req });
const { perform } = getEnveloped({ req });
let payload = '';

req.on('data', chunk => {
Expand All @@ -29,26 +29,8 @@ const server = createServer((req, res) => {

req.on('end', async () => {
const { query, variables } = JSON.parse(payload);
const document = parse(query);
const validationErrors = validate(schema, document);

if (validationErrors.length > 0) {
res.end(
JSON.stringify({
errors: validationErrors,
})
);

return;
}

const context = await contextFactory();
const result = await execute({
document,
schema,
variableValues: variables,
contextValue: context,
});
const result = await perform({ query, variables });

res.end(JSON.stringify(result));
});
Expand Down
Loading