Skip to content
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

New error extension http for setting status/headers in context, resolvers #6857

Merged
merged 5 commits into from
Aug 29, 2022

Conversation

glasser
Copy link
Member

@glasser glasser commented Aug 26, 2022

You can now add a Partial<HTTPGraphqlHead> as an http error
extension, which provides an easier way of setting HTTP response headers
or status codes. These are honored when thrown from resolvers and
context functions (and are also used internally to implement bad
request errors etc).

Multiple resolver errors can have http extensions to set status code
and distinct headers separately; we do not commit to the semantics of
what happens if multiple errors set the status code or set the same
header.

Now that you have more control over context error handling, simplify
the default behavior: if the error thrown from context is not a
GraphQLError with an http extension with a status, the default
status code is 500 rather than sometimes being 400 based on
extensions.code.

Only prepend Context creation failed: to the error message if the
error is not already a GraphQLError. This still keeps the helpful
message for developers while allowing you to remove it if you don't want
it to be visible in your app.

Fixes #6140. Fixes #5636. Fixes #6840.

@netlify
Copy link

netlify bot commented Aug 26, 2022

Deploy Preview for apollo-server-docs ready!

Name Link
🔨 Latest commit 1f44004
🔍 Latest deploy log https://app.netlify.com/sites/apollo-server-docs/deploys/630d4b5d753a8b0009c6a9f0
😎 Deploy Preview https://deploy-preview-6857--apollo-server-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site settings.

@codesandbox-ci
Copy link

codesandbox-ci bot commented Aug 26, 2022

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 1f44004:

Sandbox Source
Apollo Server Typescript Configuration
Apollo Server Configuration

@glasser glasser force-pushed the glasser/v4-error-http-context-improvements branch 2 times, most recently from 8962d40 to e6f450c Compare August 26, 2022 21:35
…olvers

You can now add a `Partial<HTTPGraphqlHead>` as an `http` error
extension, which provides an easier way of setting HTTP response headers
or status codes. These are honored when thrown from resolvers and
`context` functions (and are also used internally to implement bad
request errors etc).

Multiple resolver errors can have `http` extensions to set status code
and distinct headers separately; we do not commit to the semantics of
what happens if multiple errors set the status code or set the same
header.

Now that you have more control over `context` error handling, simplify
the default behavior: if the error thrown from `context` is not a
`GraphQLError` with an `http` extension with a `status`, the default
status code is 500 rather than sometimes being 400 based on
`extensions.code`.

Only prepend `Context creation failed: ` to the error message if the
error is not already a GraphQLError. This still keeps the helpful
message for developers while allowing you to remove it if you don't want
it to be visible in your app.

Fixes #6140. Fixes #5636. Fixes #6840.
@glasser glasser force-pushed the glasser/v4-error-http-context-improvements branch from e6f450c to d44b9e0 Compare August 26, 2022 21:46
@glasser glasser changed the title checkpoint for error/http/context improvements New error extension http for setting status/headers in context, resolvers Aug 26, 2022
@glasser glasser marked this pull request as ready for review August 26, 2022 21:46
@glasser glasser requested review from rkoron007 and trevor-scheer and removed request for rkoron007 August 26, 2022 21:47
Copy link
Contributor

@rkoron007 rkoron007 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested some changes for tone :)

docs/source/data/errors.mdx Outdated Show resolved Hide resolved
docs/source/data/errors.mdx Outdated Show resolved Hide resolved
docs/source/data/errors.mdx Outdated Show resolved Hide resolved
docs/source/data/errors.mdx Outdated Show resolved Hide resolved
docs/source/data/errors.mdx Outdated Show resolved Hide resolved
docs/source/data/errors.mdx Outdated Show resolved Hide resolved
docs/source/data/errors.mdx Outdated Show resolved Hide resolved
docs/source/data/errors.mdx Outdated Show resolved Hide resolved
docs/source/data/errors.mdx Outdated Show resolved Hide resolved
docs/source/data/resolvers.mdx Outdated Show resolved Hide resolved
@glasser glasser enabled auto-merge (squash) August 29, 2022 23:27
@glasser glasser merged commit 15b1cb2 into version-4 Aug 29, 2022
@glasser glasser deleted the glasser/v4-error-http-context-improvements branch August 29, 2022 23:28
glasser pushed a commit that referenced this pull request Aug 29, 2022
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to version-4, this PR will be updated.

⚠️⚠️⚠️⚠️⚠️⚠️

`version-4` is currently in **pre mode** so this branch has prereleases rather than normal releases. If you want to exit prereleases, run `changeset pre exit` on `version-4`.

⚠️⚠️⚠️⚠️⚠️⚠️

# Releases
## @apollo/[email protected]

### Patch Changes

-   [#6857](#6857) [`15b1cb2e9`](15b1cb2) Thanks [@glasser](https://github.com/glasser)! - Errors thrown in resolvers and context functions can use `extensions.http` to affect the response status code and headers. The default behavior when a context function throws is now to always use status code 500 rather than comparing `extensions.code` to `INTERNAL_SERVER_ERROR`.

-   Updated dependencies \[[`15b1cb2e9`](15b1cb2)]:
    -   @apollo/[email protected]

## @apollo/[email protected]

### Patch Changes

-   [#6857](#6857) [`15b1cb2e9`](15b1cb2) Thanks [@glasser](https://github.com/glasser)! - Errors thrown in resolvers and context functions can use `extensions.http` to affect the response status code and headers. The default behavior when a context function throws is now to always use status code 500 rather than comparing `extensions.code` to `INTERNAL_SERVER_ERROR`.

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Comment on lines +620 to +626
There are three ways to change an HTTP status code or set custom response headers, you can: throw an error in a resolver, throw an error in your `context` function, or write a [plugin](/apollo-server/integrations/plugins).

While Apollo Server does enable you to set HTTP status codes based on errors thrown by resolvers, best practices for GraphQL over HTTP encourage sending 200 whenever an operation executes. So, we don't recommend using this mechanism in resolvers, just in the `context` function or in a plugin hooking into an early stage of the request pipeline.

Be aware that GraphQL client libraries might not treat all response status codes the same, so it will be up to your team to decide which patterns to use.

To change the HTTP status code and response headers based on an error thrown in either a resolver or `context` function, throw a `GraphQLError` with an `http` extension, like so:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@glasser Maybe we should present the resolver example after the plugin example if it's not our official recommendation?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, my intention is mostly to say that setting the status code from errors is bad, less so than headers.

@@ -450,6 +450,33 @@ context: async () => ({
}
```

#### Throwing errors in `context`

By default, if your `context` function throws an error, Apollo Server returns that error to the user in a JSON response with an HTTP status code of 500. If the thrown error is not a `GraphQLError`, the error's message will be prepended with `"Context creation failed: "`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra whitespace

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After the colon in the string? That's intentional and accurate.
I see an extra space after JSON, I can fix that though I don't think it makes a difference when rendered...

Comment on lines +1321 to +1326
In Apollo Server 3, if your `context` function throws, then the string `"Context creation failed: "` is *always* prepended to its message, and the error is rendered with HTTP status code 500 (if the error is a GraphQLError with `extensions.code` equal to `INTERNAL_SERVER_ERROR`) or 400. You cannot select a different HTTP status code or control HTTP response headers.

In Apollo Server 4, if either the `resolveOperation` or `execute` function throws an error, that error is rendered with the HTTP status code 500 (rather than 400). Note that the `execute` function commonly returns a non-empty list of errors rather than throwing an explicit error.

In Apollo Server 4, if your `context` function throws, the string `"Context creation failed: "` is only prepended to the message if the thrown error was not a `GraphQLError`. There is no special-casing of `extensions.code`; instead, you can use [`extensions.http`](./data/errors/#setting-http-status-code-and-headers) to set the HTTP status code or headers. If this extension is not provided, the status code defaults to 500 (not 400).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 2 paragraphs about errors thrown during context creation seem oddly broken up by this paragraph between them.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True. Also resolveOperation isn't actually a thing.

glasser added a commit that referenced this pull request Oct 3, 2022
@github-actions github-actions bot mentioned this pull request Oct 10, 2022
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 20, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants