Michael Giovanni Pumo
Michael Giovanni Pumo

Reputation: 14774

Show Apollo mutation error to user in Vue.js?

I am using Vue.js with Vue-Apollo and initiating a User mutation to sign in a user. I am using the graph.cool service.

I have a request pipeline function setup to catch some errors, like an invalid email.

When the request is made with bad / invalid input, my error catch() fires (as expected) and in the network tab I can see the JSON for the custom errors messages. But how do I access these errors / response from within the catch if an error is triggered from graph.cool?

Example:

signin () {
  const email = this.email
  const password = this.password

  this.$apollo.mutate({
    mutation: signinMutation,
    variables: {
      email,
      password
    }
  })
  .then((data) => {
    // This never fires on an error, so I can't 
    // show the user the errors in the network repsonse.
    console.log(data) 
  })
  .catch((error) => {
    // Error in this part fires in the console 
    // but I'm unable to show the JSON response 
    // errors because the 'then()' above doesn't execute.
    console.error(error)
  })
}

I get the following error for an unrecognised user:

Error: GraphQL error: No user found with that information at new ApolloError (eval at (app.js:956), :34:28) at eval (eval at (app.js:1353), :139:33) at

Any idea how to show the errors in the response from within the catch()?

I can literally see the errors I want to show to the user in the response on the network tab here:

enter image description here

...but I can't figure out how to do it.

Any help much appreciated! Thank you.

Upvotes: 5

Views: 3671

Answers (2)

Michael Giovanni Pumo
Michael Giovanni Pumo

Reputation: 14774

So, it looks as though I was handling this the wrong way by barking up the wrong tree.

The key to the answer was examining the error from the .catch() with console.dir(error). This revealed some useful keys...namely:

error.graphQLErrors[0]

So all in all, the corrected code looks like this:

signin () {
  const email = this.email
  const password = this.password

  this.$apollo.mutate({
    mutation: signinMutation,
    variables: {
      email,
      password
    }
  })
  .then(data => {
    console.log(data)
  })
  .catch(error => {
    console.log(graphQLErrorMessages(error))
  })
}

The graphQLErrorMessages() function is a helper I wrote, so that I can reuse this in other .catch() blocks:

function graphQLErrorMessages (errorsFromCatch) {
  const errors = errorsFromCatch.graphQLErrors[0]
  const messages = []

  if (errors.hasOwnProperty('functionError')) {
    const customErrors = JSON.parse(errors.functionError)
    messages.push(...customErrors.errors)
  } else {
    messages.push(errors.message)
  }

  return messages
}

It returns an array of error messages (which is what I needed) but you could format this any way you like.

It might be a little https://graph.cool specific in its logic (I'm not so sure), but I hope this ends up helping someone also stuck in a similar situation!

Upvotes: 7

Baer
Baer

Reputation: 3780

I may be misunderstanding your question so please comment and correct me if I am but it looks like you may be having trouble with Promises more than with Vue or GraphQL.

Just like in a try...catch statement, once you catch an error, your program will continue to execute unless you re-throw the error. For example:

This Catches

try { 
  codeThatThrowsAnError();
} catch(e) {
  // Do Nothing
}

This re-throws

try { 
  codeThatThrowsAnError();
} catch(e) {
  throw new Error("Err 135: I failed")
}

Similarly, in Promise land, you can either catch the error and move like you have in your example, or you can re-throw. What you may be missing is that anything you return from a catch statement will be used in the next then. For example:

somethingReturningAFailedPromise()
  .then(doWork)
  .catch((err) => {
    return "I'm a New Value"
  })
  .then(console.log)

//=> "I'm a New Value"

It sounds to me like what you need is a data function that is more resilient to failure like the following:

const getUserProfile = (id) => {
  return fetchUserData(id)
    .catch((err) => {
      logError(err);
      return {};
    })
}

Upvotes: -1

Related Questions