Skip to content

Commit

Permalink
chore(docs): add return execution errors example (#1079)
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonkuhrt authored Sep 10, 2024
1 parent 61fa1fc commit 3f31e18
Show file tree
Hide file tree
Showing 45 changed files with 515 additions and 110 deletions.
7 changes: 6 additions & 1 deletion examples/$/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,20 @@ export const showJson = (value: unknown) => {

export const serveSchema = async (input: { schema: GraphQLSchema }) => {
const { schema } = input
const yoga = createYoga({ schema })
const yoga = createYoga({ schema, logging: false, maskedErrors: false })
const server = createServer(yoga) // eslint-disable-line
const port = await getPort({ port: [3000, 3001, 3002, 3003, 3004] })
const url = new URL(`http://localhost:${String(port)}/graphql`)
let runState = true
server.listen(port)
await new Promise((resolve) =>
server.once(`listening`, () => {
resolve(undefined)
})
)
const stop = async () => {
if (!runState) return
runState = false
await new Promise((resolve) => {
server.close(resolve)
setImmediate(() => {
Expand All @@ -45,6 +48,8 @@ export const serveSchema = async (input: { schema: GraphQLSchema }) => {
})
}

process.once('beforeExit', stop)

return {
yoga,
server,
Expand Down
8 changes: 6 additions & 2 deletions examples/$/schemas/pokemon/schema.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import SchemaBuilder from '@pothos/core'
import SimpleObjectsPlugin from '@pothos/plugin-simple-objects'
import ZodPlugin from '@pothos/plugin-zod'

type Trainer = {
id: number
Expand All @@ -23,7 +24,7 @@ const builder = new SchemaBuilder<{
}
}
}>({
plugins: [SimpleObjectsPlugin],
plugins: [SimpleObjectsPlugin, ZodPlugin],
})

type Database = {
Expand Down Expand Up @@ -97,7 +98,10 @@ builder.mutationField(`addPokemon`, (t) =>
t.field({
type: Pokemon,
args: {
name: t.arg.string({ required: true }),
name: t.arg.string({
required: true,
validate: { minLength: [1, { message: 'Pokemon name cannot be empty.' }] },
}),
hp: t.arg.int({ required: true }),
attack: t.arg.int({ required: true }),
defense: t.arg.int({ required: true }),
Expand Down
10 changes: 5 additions & 5 deletions examples/__outputs__/output|output_envelope.output.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
headers: Headers {
connection: 'keep-alive',
'content-length': '119',
'x-served-by': 'cache-yul1970035-YUL',
'x-served-by': 'cache-yul1970023-YUL',
'accept-ranges': 'bytes',
date: 'Sun, 08 Sep 2024 18:13:26 GMT',
'content-type': 'application/graphql-response+json; charset=utf-8',
Expand All @@ -32,13 +32,13 @@
'alt-svc': 'h3=":443"; ma=86400',
'access-control-allow-origin': '*',
'x-powered-by': 'Stellate',
age: '176284',
age: '185021',
'cache-control': 'public, s-maxage=2628000, stale-while-revalidate=2628000',
'x-cache': 'HIT',
'x-cache-hits': '13',
'x-cache-hits': '38',
'gcdn-cache': 'HIT',
'stellate-rate-limit-budget-remaining': '49',
'stellate-rate-limit-rules': '"IP limit";type="RequestCount";budget=50;limited=?0;remaining=49;refill=60',
'stellate-rate-limit-budget-remaining': '36',
'stellate-rate-limit-rules': '"IP limit";type="RequestCount";budget=50;limited=?0;remaining=36;refill=6',
'stellate-rate-limit-decision': 'pass',
'stellate-rate-limit-budget-required': '5',
'content-encoding': 'br'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@
{
errors: [
ContextualError: There was an error in the extension "anonymous" (use named functions to improve this error message) while running hook "encode".
at runPipeline (/some/path/to/runPipeline.ts:76:18)
at async Object.run (/some/path/to/main.ts:286:22)
at async run (/some/path/to/client.ts:256:20)
at async executeRootType (/some/path/to/client.ts:185:12)
at async executeRootTypeField (/some/path/to/client.ts:216:20)
at async <anonymous> (/some/path/to/output|output_envelope_envelope-error__envelope-error.ts:24:16) {
at runPipeline (/some/path/to/runPipeline.ts:XX:XX)
at async Object.run (/some/path/to/main.ts:XX:XX)
at async run (/some/path/to/client.ts:XX:XX)
at async executeRootType (/some/path/to/client.ts:XX:XX)
at async executeRootTypeField (/some/path/to/client.ts:XX:XX)
at async <anonymous> (/some/path/to/output|output_envelope_envelope-error__envelope-error.ts:XX:XX) {
context: {
hookName: 'encode',
source: 'extension',
extensionName: 'anonymous'
},
cause: Error: Something went wrong.
at <anonymous> (/some/path/to/output|output_envelope_envelope-error__envelope-error.ts:20:9)
at applyBody (/some/path/to/main.ts:310:28)
at <anonymous> (/some/path/to/output|output_envelope_envelope-error__envelope-error.ts:XX:XX)
at applyBody (/some/path/to/main.ts:XX:XX)
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@


ContextualError: There was an error in the extension "anonymous" (use named functions to improve this error message) while running hook "encode".
at runPipeline (/some/path/to/runPipeline.ts:76:18)
at async Object.run (/some/path/to/main.ts:286:22)
at async run (/some/path/to/client.ts:256:20)
at async executeRootType (/some/path/to/client.ts:185:12)
at async executeRootTypeField (/some/path/to/client.ts:216:20)
at async <anonymous> (/some/path/to/output|output_envelope_envelope_error-throw__envelope-error-throw.ts:22:1) {
at runPipeline (/some/path/to/runPipeline.ts:XX:XX)
at async Object.run (/some/path/to/main.ts:XX:XX)
at async run (/some/path/to/client.ts:XX:XX)
at async executeRootType (/some/path/to/client.ts:XX:XX)
at async executeRootTypeField (/some/path/to/client.ts:XX:XX)
at async <anonymous> (/some/path/to/output|output_envelope_envelope_error-throw__envelope-error-throw.ts:XX:XX) {
context: {
hookName: 'encode',
source: 'extension',
extensionName: 'anonymous'
},
cause: Error: Something went wrong.
at <anonymous> (/some/path/to/output|output_envelope_envelope_error-throw__envelope-error-throw.ts:18:9)
at applyBody (/some/path/to/main.ts:310:28)
at <anonymous> (/some/path/to/output|output_envelope_envelope_error-throw__envelope-error-throw.ts:XX:XX)
at applyBody (/some/path/to/main.ts:XX:XX)
}

Node.js vXX.XX.XX
17 changes: 17 additions & 0 deletions examples/__outputs__/output|output_return-error.output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---------------------------------------- SHOW ----------------------------------------
ContextualError: There was an error in the extension "anonymous" (use named functions to improve this error message) while running hook "encode".
at runPipeline (/some/path/to/runPipeline.ts:XX:XX)
at async Object.run (/some/path/to/main.ts:XX:XX)
at async run (/some/path/to/client.ts:XX:XX)
at async executeRootType (/some/path/to/client.ts:XX:XX)
at async executeRootTypeField (/some/path/to/client.ts:XX:XX)
at async <anonymous> (/some/path/to/output|output_return-error.ts:XX:XX) {
context: {
hookName: 'encode',
source: 'extension',
extensionName: 'anonymous'
},
cause: Error: Something went wrong.
at <anonymous> (/some/path/to/output|output_return-error.ts:XX:XX)
at applyBody (/some/path/to/main.ts:XX:XX)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---------------------------------------- SHOW ----------------------------------------
ContextualAggregateError: One or more errors in the execution result.
at handleOutput (/some/path/to/handleOutput.ts:XX:XX)
at run (/some/path/to/client.ts:XX:XX)
at process.processTicksAndRejections (node:internal/process/task_queues:XX:XX)
at async executeRootType (/some/path/to/client.ts:XX:XX)
at async executeRootTypeField (/some/path/to/client.ts:XX:XX)
at async <anonymous> (/some/path/to/output|output_return-error_return-error-execution__return-error-execution.ts:XX:XX) {
context: {},
cause: undefined,
errors: [
GraphQLError: [
{
"code": "too_small",
"minimum": 1,
"type": "string",
"inclusive": true,
"exact": false,
"message": "Pokemon name cannot be empty.",
"path": [
"name"
]
}
]
at <anonymous> (/some/path/to/graphqlHTTP.ts:XX:XX)
at Array.map (<anonymous>)
at parseExecutionResult (/some/path/to/graphqlHTTP.ts:XX:XX)
at Object.unpack (/some/path/to/core.ts:XX:XX)
at process.processTicksAndRejections (node:internal/process/task_queues:XX:XX)
at async runHook (/some/path/to/runHook.ts:XX:XX) {
path: [ 'addPokemon' ],
locations: undefined,
extensions: [Object: null prototype] {}
}
]
}
---------------------------------------- SHOW ----------------------------------------
ContextualError: There was an error in the extension "anonymous" (use named functions to improve this error message) while running hook "encode".
at runPipeline (/some/path/to/runPipeline.ts:XX:XX)
at process.processTicksAndRejections (node:internal/process/task_queues:XX:XX)
at async Object.run (/some/path/to/main.ts:XX:XX)
at async run (/some/path/to/client.ts:XX:XX)
at async executeRootType (/some/path/to/client.ts:XX:XX)
at async executeRootTypeField (/some/path/to/client.ts:XX:XX)
at async <anonymous> (/some/path/to/output|output_return-error_return-error-execution__return-error-execution.ts:XX:XX) {
context: {
hookName: 'encode',
source: 'extension',
extensionName: 'anonymous'
},
cause: Error: Something went wrong.
at <anonymous> (/some/path/to/output|output_return-error_return-error-execution__return-error-execution.ts:XX:XX)
at applyBody (/some/path/to/main.ts:XX:XX)
at process.processTicksAndRejections (node:internal/process/task_queues:XX:XX)
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
headers: Headers {
accept: 'application/graphql-response+json; charset=utf-8, application/json; charset=utf-8',
'content-type': 'application/json',
'x-sent-at-time': '1725995489078'
'x-sent-at-time': '1726004226733'
},
signal: undefined,
method: 'post',
Expand Down
26 changes: 14 additions & 12 deletions examples/output|output_envelope_envelope-error__envelope-error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,22 @@ import { Atlas } from './$/generated-clients/atlas/__.js'
import { show } from './$/helpers.js'

// dprint-ignore
const atlas = Atlas.create({
output: {
envelope: {
errors: {
// ^^^^^^
execution: true, // default
other: true,
const atlas = Atlas
.create({
output: {
envelope: {
errors: {
// ^^^^^^
execution: true, // default
other: true,
},
},
},
},
}).use(({ encode: _ }) => {
throw new Error(`Something went wrong.`)
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
})
})
.use(({ encode: _ }) => {
throw new Error(`Something went wrong.`)
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
})

const result = await atlas.query.continents({ name: true })

Expand Down
28 changes: 28 additions & 0 deletions examples/output|output_return-error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* This example shows how to configure output to have errors returned instead of e.g. thrown.
*/

import { Atlas } from './$/generated-clients/atlas/__.js'
import { show } from './$/helpers.js'

// dprint-ignore
const atlas = Atlas
.create({
output: {
envelope: false,
defaults: {
errorChannel: `return`,
},
},
})
// dprint-ignore
.use(({ encode: _ }) => {
throw new Error(`Something went wrong.`)
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
})

const result = await atlas.query.continents({ name: true })
type _result = typeof result
// ^?

show(result)
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* This example shows how to configure output to have only certain kinds of errors returned while others thrown.
*/

import { Pokemon } from './$/generated-clients/pokemon/__.js'
import { serveSchema, show } from './$/helpers.js'
import { schema } from './$/schemas/pokemon/schema.js'

const server = await serveSchema({ schema: schema })

const pokemon = Pokemon
.create({
schema: server.url,
output: {
envelope: false,
errors: {
execution: `return`,
other: `throw`,
},
},
})

// 1. The __execution__ error of an empty Pokemon name will be ***returned***.

type _result = typeof result
const result = await pokemon.mutation.addPokemon({
$: { name: ``, hp: 1, defense: 0, attack: 0 },
name: true,
})
show(result)

// 2. The __other__ error, in this case from the inline extension, will be ***thrown***.

try {
await pokemon
.use(({ encode: _ }) => {
throw new Error(`Something went wrong.`)
})
.query
.pokemon({ name: true })
} catch (error) {
show(error)
}

await server.stop()
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,7 @@
"dependencies": {
"@graphql-typed-document-node/core": "^3.2.0",
"@molt/command": "^0.9.0",
"is-plain-obj": "^4.1.0",
"zod": "^3.23.8"
"is-plain-obj": "^4.1.0"
},
"peerDependencies": {
"@dprint/formatter": "^0.3.0 || ^0.4.0",
Expand All @@ -110,6 +109,7 @@
"@arethetypeswrong/cli": "^0.16.2",
"@pothos/core": "^4.2.0",
"@pothos/plugin-simple-objects": "^4.1.0",
"@pothos/plugin-zod": "^4.1.0",
"@tsconfig/node20": "^20.1.4",
"@tsconfig/strictest": "^2.0.5",
"@types/body-parser": "^1.19.5",
Expand Down Expand Up @@ -146,6 +146,7 @@
"typescript": "^5.6.2",
"typescript-eslint": "^8.5.0",
"vitepress": "^1.3.4",
"vitest": "^2.0.5"
"vitest": "^2.0.5",
"zod": "^3.23.8"
}
}
Loading

0 comments on commit 3f31e18

Please sign in to comment.