Here I have a resolver for coupon code redemption. It should throw an error when the code doesn't exist or has a claim. Apollo server provides a few errors we can use to communicate errors to a client.
import { OperationContext } from "../../../graphql/OperationContext" import { assertUserId } from "../../../auth/assertUserId" import * as appSumoCodesDb from "../db" import { UserInputError } from "apollo-server-lambda" interface Input { code: string } export const redeemAppSumoCode = async ( _: any, { input: { code } }: { input: Input }, context: OperationContext ) => { const userId = assertUserId(context) const appSumoCode = await appSumoCodesDb.getAppSumoCodeById(code) if (!appSumoCode || appSumoCode.userId !== userId) { throw new UserInputError("Invalid code") } // ... }
We can go to the source code and see that they all extend ApolloErro. So if we need a custom error, we can copy one of the classes from here and change the name with a code.
export class UserInputError extends ApolloError { constructor(message: string, extensions?: Record<string, any>) { super(message, "BAD_USER_INPUT", extensions) Object.defineProperty(this, "name", { value: "UserInputError" }) } }
Apollo Server always responds with 200, but if API threw an error, we'll receive errors with a response. I formatted the error to include only the message and extensions. If we want to provide extra information, we can add an object as a second parameter to ApolloError, and it will appear in the extensions object. To omit stack trace from extension, set NODE_ENV
to production.
const server = new ApolloServer({ typeDefs, resolvers, // ... formatError: ({ message, extensions }) => { return { message, extensions, } }, })
I run Apollo Server on AWS Lambda and use Sentry for error monitoring. Don't forget to pass ignoreSentryErrors, otherwise, your lambda will crash if you reach Sentry's quote.
exports.handler = Sentry.AWSLambda.wrapHandler(server.createHandler(), { ignoreSentryErrors: true, })
Top comments (0)