Errors
Custom Errors
Shield, by default, catches all errors thrown during resolver execution. This way we can be 100% sure none of your internal logic can be exposed to the client if it was not meant to be.
To return custom error messages to your client, you can return error instead of throwing it. This way, Shield knows it's not a bug but rather a design decision under control. Besides returning an error you can also return a string
representing a custom error message.
You can return custom error from resolver or from rule itself. Rules that return error are treated as failing, therefore not processing any further resolvers.
const typeDefs = /* GraphQL */ `
type Query {
customErrorInResolver: String
customErrorInRule: String
}
`
const resolvers = {
Query: {
customErrorInResolver() {
return new Error('Custom error message from resolver.')
},
customErrorMessageInRule() {
// Querying is stopped because rule returns an error
console.log("This won't be logged.")
return "you won't see me!"
},
customErrorInRule() {
// Querying is stopped because rule returns an error
console.log("This won't be logged.")
return "you won't see me!"
},
},
}
const ruleWithCustomError = rule()(async (parent, args, ctx, info) => {
return new Error('Custom error from rule.')
})
const ruleWithCustomErrorMessage = rule()(async (parent, args, ctx, info) => {
return 'Custom error message from rule.'
})
const permissions = shield({
Query: {
customErrorInRule: ruleWithCustomError,
customErrorMessageInRule: ruleWithCustomErrorMessage,
},
})
const server = GraphQLServer({
typeDefs,
resolvers,
middlewares: [permissions],
})
Errors thrown in resolvers can be tracked using debug
option. This way Shield ensures your code is production ready at all times.
If you wish to see errors thrown inside resolvers, you can set allowExternalErrors
option to true
. This way, Shield won't hide custom errors thrown during query resolving.
Global Fallback Error
GraphQL Shield allows you to set a globally defined fallback error that is used instead of Not Authorised!
default response. This might be particularly useful for localization. You can use string
or even custom Error
to define it.
const permissions = shield(
{
Query: {
items: allow,
},
},
{
fallbackError: 'To je napaka!', // meaning "This is a mistake" in Slovene.
},
)
const permissions = shield(
{
Query: {
items: allow,
},
},
{
fallbackError: new CustomError('You are something special!'),
},
)
const permissions = shield(
{
Query: {
items: allow,
},
},
{
async fallbackError(thrownThing, parent, args, context, info) {
if (thrownThing instanceof ApolloError) {
// expected errors
return thrownThing
}
if (thrownThing instanceof Error) {
// unexpected errors
console.error(thrownThing)
await Sentry.report(thrownThing)
return new ApolloError('Internal server error', 'ERR_INTERNAL_SERVER')
}
// what the hell got thrown
console.error('The resolver threw something that is not an error.')
console.error(thrownThing)
return new ApolloError('Internal server error', 'ERR_INTERNAL_SERVER')
},
},
)