Reputation:
I'm trying to move from Rest API to GraphQL using Express + Mongoose on server and React + Apollo on client.
async resolve(_, { email, password, passwordConfirmation }) { // Sign Up mutation
const user = new User({ email });
user.password = password;
user.passwordConfirmation = passwordConfirmation;
try{
const createdUser = await user.save();
return createdUser;
} catch(error) {
console.log(error); // Returns errors object like {email: {message: 'E-mail is required'}}
throw new Error(error); // But on the client there is a string with all errors
}
}`
How can I handle the whole object of errors on the client?
Upvotes: 5
Views: 2859
Reputation: 3774
You can also use renderProps in react-apollo which gives you error and loading states in an object in the second argument.
import React, { Component } from 'react';
import { Mutation } from 'react-apollo';
import gql from 'graphql-tag';
import Error from './ErrorMessage';
const LOGIN_MUTATION = gql`
mutation LOGIN_MUTATION($email: String!, $password: String!) {
signin(email: $email, password: $password) {
id
email
name
}
}
`;
class Login extends Component {
state = {
name: '',
password: '',
email: '',
};
saveToState = e => {
this.setState({ [e.target.name]: e.target.value });
};
render() {
return (
<Mutation
mutation={LOGIN_MUTATION}
variables={this.state}
>
{(login, { error, loading }) => (
<form
method="post"
onSubmit={async e => {
e.preventDefault();
await login();
this.setState({ name: '', email: '', password: '' });
}}
>
<fieldset disabled={loading}>
<h2>Sign into your account</h2>
<Error error={error} />
<label htmlFor="email">
Email
<input
type="email"
name="email"
placeholder="email"
value={this.state.email}
onChange={this.saveToState}
/>
</label>
<label htmlFor="password">
Password
<input
type="password"
name="password"
placeholder="password"
value={this.state.password}
onChange={this.saveToState}
/>
</label>
<button type="submit">Sign In!</button>
</fieldset>
</form>
)}
</Mutation>
);
}
}
export default Login;
Hope this helps!
Upvotes: 1
Reputation: 1288
The Apollo client returns a promise when you make a mutation. The errors from that promise can be accessed in the catch block of the mutation's resultant promise. See my example below.
If there are errors from my login mutation, I will access them in the catch block of the promise that is returned and then set those errors to local state in the component. From there the errors can be rendered if they exist, or even passed down to a child component to be rendered if you like. Please note that errors are usually returned in an array.
class LoginForm extends Component {
constructor(props) {
super(props);
this.state = { errors: [] };
}
onSubmit({ email, password }) {
this.props.mutate({
variables: { email, password },
refetchQueries: [{ query }]
}).catch(res => {
const errors = res.graphQLErrors.map(error => error.message);
this.setState({ errors });
});
}
render() {
return (
<div>
<AuthForm
errors={this.state.errors}
onSubmit={this.onSubmit.bind(this)}
/>
</div>
);
}
}
export default graphql(query)(
graphql(mutation)(LoginForm)
);
Upvotes: 6