Search code examples
javascriptnode.jsreactjskoaapollo

How to handle backend errors from Node/Koa on frontend apollo-client


My frontend, using apollo-client, throws an exception when the backend returns an error after a request.

When the node server receives a request, I check the validity of the request's token using koa middleware. If the token is valid, the request is forwarded to the next middleware. If the token is invalid, I want to return a 401 access denied error to the client. To do this, I followed Koa's error documentation located here.

The code for the error handling middleware I wrote:

function userIdentifier() {
  return async (ctx, next) => {
    const token = ctx.request.headers.authorization

    try {
      const payload = checkToken(token)
      ctx.user = {
        id: payload.userId,
        exp: payload.exp,
        iat: payload.iat,
      }
    } catch (error) {
      ctx.user = undefined
      ctx.throw(401, "access_denied")
      // throw new Error("access_denied")
    }

    await next()
  }
}

This seemingly works on the backend, but not on the frontend. When the frontend receives this error, a JavaScript runtime error occurs. I am not sure what causes this.

enter image description here

Note, the unexpected "a" is the same "a" found in ctx.throw(401, "access_denied"). If it were instead ctx.throw(401, "x") the frontend shows "unexpected token x" instead.

The frontend code where the errors happens:

enter image description here

In an attempt to fix this, I followed Apollo's error handling documentation and used apollo-link-error.

const errorLink = onError(props => {
  const { graphQLErrors, networkError } = props
  console.log("ON ERROR", props)
  if (graphQLErrors)
    graphQLErrors.map(({ message, locations, path }) =>
      console.log(
        `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
      )
    )
  if (networkError) console.log(`[Network error]: ${networkError}`)
})

Then I combine all links and create the Apollo client like this:

const link = ApolloLink.from([errorLink, authLink, httpLink])

export const client = new ApolloClient({
  link,
  cache: new InMemoryCache(),
})

The output of the debugging log in apollo-link-error is as follows:

enter image description here

Related Documents

Someone seems to be having an identical error, but a solution was not listed.


Solution

  • I found that the errors were handled correctly on the frontend when I began using this library on the backend: https://github.com/jeffijoe/koa-respond

    Using just ctx.unauthenticated()

    But I would still like to know more about how to return json/object-based errors with koa without a plugin helping