1
votes

I'm trying to display a simple "Email and password do not match" error on a login form, but am having trouble and not sure if where I've gone wrong is on the server or in my React app. I thought I'd post here as I'm unsure which github repo would be appropriate. Here's the resolver on the server:

// Schema definition:

type Mutation {
   loginViewer(credentials: AUTH_CREDENTIALS): SignInPayload!
}

type SignInPayload {
   token: String
   expires: Int
   requiresReset: Boolean
}

// Mapping the mutation to the resolver:

Mutation: {
   loginViewer: loginViewerMutation,
},


// Resolver:

const loginViewerMutation = async (obj, args) => {
   const { credentials } = args
   const user = await User.findOne({ email })
   if (!user) throw new GraphQLError('Email and password do not match')
   const matches = await user.comparePassword(password)
   if (!matches) throw new GraphQLError('Email and password do not match')
   return createJWT(user)
}

Then, the mutation as it's called within my Login component:

const mutation = gql`
   mutation LoginViewer($password: String!, $email: String!) {
      loginViewer(credentials: { email: $email, password: $password }) {
         token
         expires
         requiresReset
      }
   }
`

export class Login extends React.Component {
   handleLogin = (credentials) => {
      this.props
         .mutate({ variables: { ...credentials } })
         .then(() => {
            // ...
         })
         .catch((error) => {
            console.log(error.message)
            console.log(error.graphQLErrors)
            // ...
         })
   }

   render() {
      // ...
   }
}

export default graqphql(mutation)(Login)

Everything works as expected when I supply the correct information. When I don't, the error that is caught doesn't contain the GraphQLErrors.

I'm using the apollo-link-error middleware with the default setup: https://www.apollographql.com/docs/link/links/error.html

My console looks like this:

enter image description here

The expected authentication error is being returned, and logged from the middleware. But, in my Login component, the error.graphQLErrors array is empty.

Where might I be going wrong here?

  • It doesn't seem right to be returning a 500 Internal Server Error --- it's behaving exactly as I want it to. Am I implementing this incorrectly on the server?

  • How are the graphQLErrors getting 'lost' between the logging middleware and the .catch(error)?

1
Can you post the code where you connect loginViewerMutation to the resolver map or where you call it? – Tal Z
@TalZ, just updated the question with more code – Good Idea
I tried reproducing a similar error with my server and didn't succeed. Not sure why. – Tal Z

1 Answers

1
votes

I asked this question on the express-graphql github repo, they quickly pointed out that the solution was removing the ! on my loginViewer mutation:

// Schema definition:

type Mutation {
   loginViewer(credentials: AUTH_CREDENTIALS): SignInPayload!
}

// Should be:

type Mutation {
   loginViewer(credentials: AUTH_CREDENTIALS): SignInPayload
}

It's expected behavior since your top-level field (loginViewer) defined as non-null. That means when error bubble up it GraphQL engine has no option except make data field equals to null:

Since Non-Null type fields cannot be null, field errors are propagated to be handled by the parent field. If the parent field may be null then it resolves to null, otherwise if it is a Non-Null type, the field error is further propagated to it’s parent field.

If all fields from the root of the request to the source of the error return Non-Null types, then the "data" entry in the response should be null.

http://facebook.github.io/graphql/draft/#sec-Errors-and-Non-Nullability

If data is null that means the entire request is failed and express-graphql response with 500.