Skip to content

Commit

Permalink
(docs) Add information on rewriteError to the errors.md.
Browse files Browse the repository at this point in the history
This adds additional clarity fro the new functionality provided in #1639.
  • Loading branch information
abernix committed Apr 28, 2019
1 parent e99a99a commit b7bd0a3
Showing 1 changed file with 132 additions and 1 deletion.
133 changes: 132 additions & 1 deletion docs/source/features/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,17 @@ new ApolloError(message, code, additionalProperties);

## Masking and logging errors

### For the client response

The Apollo server constructor accepts a `formatError` function that is run on each error passed back to the client. This can be used to mask errors as well as for logging.
This example demonstrates masking (or suppressing the stacktrace):

> Note that while this changes the error which is sent to the client, it
> doesn't change the error which is sent to Apollo Engine. See the
> `rewriteError` function in the _For Apollo Engine reporting_ section below
> if this behavior is desired.
This example demonstrates masking (or suppressing the stacktrace) which is
returned to the client:

```js line=4-10
const server = new ApolloServer({
Expand All @@ -138,3 +147,125 @@ server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
```

### For Apollo Engine reporting

With the Apollo Platform, it's possible to observe error rates within Apollo
Engine, rather than simply logging them to the console. While all errors are
sent to Apollo Engine by default, depending on the severity of the error, it
may be desirable to not send particular errors which may be caused by a
user's actions. Alternatively, it may be necessary to modify or redact errors
before transmitting them.

To account for these needs, a `rewriteError` function can be provided within
the `engine` settings to Apollo Server. At a high-level, the function will
receive the error to be reported (i.e. a `GraphQLError` or an `ApolloError`)
as the first argument. The function should then return a modified form of
that error (e.g. after changing the `err.message` to remove potentially
sensitive information), or should return an explicit `null` in order to avoid
reporting the error entirely.

The following sections give some examples of various use-cases for `rewriteError`.

#### Avoid reporting lower-severity predefined errors.

If an application is utilizing the predefined errors noted above (e.g.
`AuthenticationError`, `ForbiddenError`, `UserInputError`, etc.), these can
be used with `rewriteError`.

For example, if the current server is `throw`ing the `AuthenticationError`
when a mis-typed password is supplied, an implementor can avoid reporting
this to Apollo Engine by defining `rewriteError` as follows:

```js line=5-15
const { ApolloServer, AuthenticationError } = require("apollo-server");
const server = new ApolloServer({
typeDefs, // (Not defined in this example)
resolvers, // " " " "
engine: {
rewriteError(err) {
// Return `null` to avoid reporting `AuthenticationError`s
if (err instanceof AuthenticationError) {
return null;
}

// All other errors will be reported.
return err;
}
},
});
```

This example configuration would ensure that any `AuthenticationError` which
was thrown within a resolver would only be reported to the client, and never
sent to Apollo Engine. All other errors would be transmitted to Apollo Engine
normally.

#### Avoid reporting an error based on other properties.

When generating an error (e.g. `new ApolloError("Failure!")`), the `message`
is the most common property (i.e. `err.message`, which is `Failure!` in this
case). However, any number of properties can be attached to the error (e.g.
adding a `code` property). These properties can be checked when determining
whether an error should be reported to Apollo Engine using the `rewriteError`
function as follows:

```js line=5-16
const { ApolloServer } = require("apollo-server");
const server = new ApolloServer({
typeDefs, // (Not defined in this example)
resolvers, // " " " "
engine: {
rewriteError(err) {
// Using a more stable, known error property (e.g. `err.code`) would be
// more defensive, however checking the `message` might serve most needs!
if (err.message && err.message.match(/^Known error message/) {
return null;
}

// All other errors should still be reported!
return err;
}
},
});
```
This example configuration would ensure that any error which started with
`Known error message` was not transmitted to Apollo Engine, but all other
errors would continue to be sent.
#### Redacting the error message.
If it is necessary to change the error prior to reporting it to Apollo Engine
– for example, if there is personally identifiable information in the error
`message` — the `rewriteError` function can also help.
Consider an example where the error contained a piece of information like
an API key (e.g. `throw new ApolloError("The x-api-key:12345 doesn't have
sufficient privileges.");`).
While a best practice would suggest not including such information in the
error message itself, the `rewriteError` function could be used to make sure
it it's sent to Apollo Engine and potentially revealed outside its intended
scope:
```js line=5-11
const { ApolloServer } = require("apollo-server");
const server = new ApolloServer({
typeDefs, // (Not defined in this example)
resolvers, // " " " "
engine: {
rewriteError(err) {
// Make sure that a specific pattern is removed from all error messages.
err.message = err.message.replace(/x-api-key:[A-Z0-9-]+/, "REDACTED");
return err;
}
},
});
```
In this case, the example error used above would be reported in Apollo Engine as:
```
The x-api-key:REDACTED doesn't have sufficient privileges.
```

0 comments on commit b7bd0a3

Please sign in to comment.