Skip to content

Commit

Permalink
feat: granular output config (#991)
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonkuhrt authored Aug 2, 2024
1 parent 40d51c5 commit fe50d58
Show file tree
Hide file tree
Showing 30 changed files with 1,357 additions and 809 deletions.
113 changes: 86 additions & 27 deletions DOCUMENTATION_NEXT.md
Original file line number Diff line number Diff line change
@@ -1,56 +1,115 @@
# GraphQL Request Documentation

# Return Mode
# Output

GraphQL execution has this general pattern:
The standard GraphQL execution result type in the JavaScript ecosystem (from the `graphql` package) has roughly this type:

```ts
interface GraphQLExecutionResult {
data?: object
errors?: GraphQLError[]
extensions?: []
extensions?: unknown[]
}
```

You can change the output of client methods by configuring its return mode. This allows you to tailor the client better to your specific use-case.
Graffle can return this type but also many other types depending on your configuration. For example:

The only client method that is not affected by return mode is `raw` which will _always_ return a standard GraphQL result type.
1. Return the data directly without an envelope.
1. Return all or some categories of errors (return type becomes a union).
1. Return an envelope and place all or some categories of errors into the `errors` field.
1. Throw all or some categories of errors.

Here is a summary table of the modes:
Configuration can be done at the constructor level. Method level will also be supported in the future.

| Mode | Throw Sources (no type safety) | Returns (type safe) |
| ---------------- | ------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| `graphql` | Extensions, Fetch | `GraphQLExecutionResult` |
| `graphqlSuccess` | Extensions, Fetch, GraphQLExecutionResult.errors | `GraphQLExecutionResult` with `.errors` always missing. |
| `data` (default) | Extensions, Fetch, GraphQLExecutionResult.errors | `GraphQLExecutionResult.data` |
| `dataSuccess` | Extensions, Fetch, GraphQLExecutionResult.errors, GraphQLExecutionResult.data Schema Errors | `GraphQLExecutionResult.data` without any schema errors |
| `dataAndErrors` | | `GraphQLExecutionResult.data`, errors from: Extensions, Fetch, GraphQLExecutionResult.errors |
```ts
// Constructor Level

const graffle = Graffle.create({
output: {
errors: {
execution: 'throw',
other: 'return',
},
},
})

// Method Level (planned, not implemented yet)

await graffle.query.foo({}, {
output: {
envelope: true,
},
})
```

## `graphql`
## Errors

Return the standard graphql execution output.
There are three categories of errors:

## `graphqlSuccess`
1. `execution` – Anything that went wrong during execution. Examples: invalid input given, resolver threw an error.
2. `schema` – Only present if the [schema errors](#schema-errors) are being used. Any time a result field returns an error type.
3. `other` – Anything else. Examples: network error during request, extension threw error, your anyware threw an error.

Return the standard graphql execution output. However, if there would be any errors then they're thrown as an `AggregateError`.
This mode acts like you were using [`OrThrow`](#orthrow) method variants all the time.
You can choose to output error categories in the following ways:

## `dataSuccess`
1. `throw` – Errors from category will be thrown. There is no type safety with this approach.
2. `return` – Errors from category will be returned. The return type will thus become a union type.
3. `default` – Use whatever the default is (you can change the default).

Return just the data excluding [schema errors](#schema-errors). Errors are thrown as an `AggregateError`.
This mode acts like you were using [`OrThrow`](#orthrow) method variants all the time.
## Envelope

This mode is only available when using [schema errors](#schema-errors).
You can choose to use an envelope. When you use an envelope the data will be returned in a `data` property. Additional metadata properties will be exposed:

## `data`
1. `errors` – errors that you have chosen to include in the envelope.
2. `extensions` – GraphQL execution result extensions.
3. `response` – Only present if [transport](#link-todo) is `http`. The HTTP response to the request that was sent for the given GraphQL document.

Return just the data including [schema errors](#schema-errors) (if using). Other errors are thrown as an `AggregateError`.
## Examples

**This mode is the default.**
### Standard GraphQL

## `dataAndErrors`
```ts
const graffle = Graffle.create({
output: {
envelope: {
errors: {
execution: true, // Bring execution errors into envelope.
},
},
errors: {
other: 'throw',
},
},
})

assertType<{
data: {
foo: string /* or whatever */
}
errors: GraphQLError[]
extensions: unknown[]
response: Response // Non-standard. Present when using HTTP transport.
}>(await graffle.query.foo())
```

Return a union type of data and errors. This is the most type-safe mode. It never throws.
### Full Type Safety

```ts
const graffle = Graffle.create({
output: {
defaults: {
errorChannel: 'return',
},
envelope: false,
},
})

assertType<
| string /* or whatever */
| GraphQLError
| Error
>(await graffle.query.foo())
```

# Schema Errors

Expand Down
13 changes: 7 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,12 @@
"@types/body-parser": "^1.19.5",
"@types/express": "^4.17.21",
"@types/json-bigint": "^1.0.4",
"@types/node": "^22.0.0",
"@typescript-eslint/eslint-plugin": "^7.18.0",
"@typescript-eslint/parser": "^7.18.0",
"@types/node": "^22.0.2",
"@typescript-eslint/eslint-plugin": "^8.0.0",
"@typescript-eslint/parser": "^8.0.0",
"doctoc": "^2.2.1",
"dripip": "^0.10.0",
"es-toolkit": "^1.13.1",
"eslint": "^9.8.0",
"eslint-config-prisma": "^0.6.0",
"eslint-plugin-deprecation": "^3.0.0",
Expand All @@ -133,10 +134,10 @@
"jsdom": "^24.1.1",
"json-bigint": "^1.0.0",
"publint": "^0.2.9",
"tsx": "^4.16.2",
"tsx": "^4.16.5",
"type-fest": "^4.23.0",
"typescript": "^5.5.4",
"typescript-eslint": "^7.18.0",
"vitest": "^2.0.4"
"typescript-eslint": "^8.0.0",
"vitest": "^2.0.5"
}
}
Loading

0 comments on commit fe50d58

Please sign in to comment.