Connecting GraphQL to React+Apollo

In a previous post, I discussed my learnings about the differences and similarities between GraphQL and REST. It was a tough crash course. In this post, I’ll be continuing that discussion where I learned how GraphQL communicates with React through Apollo. Here’s what I’ve learned.

Using React-Apollo, we connect our React front-end with a GraphQL API. The API contains the application schema like we discussed in the previous post. Here’s a similar schema I had to work with during the code challenge.

**Queries**
// Users: Fetches all users from the backend
type Query {
Users(where: UserWhereInput): [User]!
}
**Mutations**
// createUser: Create an account for a new user
type Mutation {
createUser(data: UserCreateInput!): User!
}
**Types**
// Data Types
type UserWhereInput {
email: String
}

type UserCreateInput {
status: Status
email: String
password: String
timeZone: String
}

type User {
id: ID!
email: String
password: String
}

Before setting up my React routers and components, I had to define my gql queries. So I played with the schema in the provided GraphiQL in-browser IDE to ensure that I fetch the proper data. More on gql later.

To fetch all the Users and their fields, I sent the user query like so. I tried three different styles.

//style A
{
Users {
id
email
password
}
}
//style B
query Users {
Users {
id
email
password
}
}
//style C
query Users($where: UserWhereInput) {
Users(where: $where) {
email
}
}

To fetch a specific User, I queried their email field

# Find (Query) a user by their email
query Users {
Users(where: {email:"sponge@bob.com"}) {
id
email
}
}
=> Response
{
"data": {
"Users": [
{
"id": "cjkn3oxymuf630980qtd0dq4y",
"email": "sponge@bob.com"
}
]
}
}
# Find (Query) a user by their email

query stukentUsers {
stukentUsers(where: {email:"empty@gmail.com"}) {
id
password
}
}
=> Response
{
"data": {
"Users": []
}
}

To create a new User, I called on the mutation type.

mutation createUser {
createUser(data: {
email: "jake@gmail.com"
}) {
id
email
}
}
=> response
{
"data": {
"Users": [
{
"id": "cjl6sr4rhsi4m0980sxq321ul",
"email": "jake@gmail.com",
}
]
}
}
/* Query All Users to ensure new User was added */
{
stukentUsers {
id
email
password
timeZone
}
}
=> response
{
"data": {
"Users": [
{
"id": "cjl6sr4rhsi4m0980sxq321ul",
"email": "jake@gmail.com",
"password": null,
}
]
}
}

To update a User, I queried the user for their ID. Then I called on the mutation type along with the field I want to update.

query stukentUsers {
stukentUsers(where: {email:"jake@gmail.com"}) {
id
email
password
}
}
=> response
{
"data": {
"Users": [
{
"id": "cjl6sr4rhsi4m0980sxq321ul",
}
]
}
}

/* Updating User's password field */
mutation updateUser {
updateUser(data: {
password: "Candie3s!@gmail.com"
}, where: {id: "cjl6sr4rhsi4m0980sxq321ul"}) {
id
password
}
}
=> response
{
"data": {
"Users": [
{
"id": "cjl6sr4rhsi4m0980sxq321ul",
"email": "jake@gmail.com",
"password": "Candie3s!"
}
]
}
}

Now that I’m able to fetch the data I need, I can start parsing my GraphQL query into a GraphQL form that’s consumed by Apollo Client. When Apollo Client asks for a GraphQL query, the query must be wrapped into an gql template tag. Here’s how I defined my queries with the gql tags

/* query.js */
import gql from "graphql-tag";
export const getEmails = gql `
query {
Users {
id
email
}
}
`;
// Find(Query) a user with a selected email. Get that User's id and create a password
export const getUsersID = gql`
query Users($where: UserWhereInput) {
Users(where: $where) {
id
email
}
}
`;

/* mutation.js */
import gql from "graphql-tag";
export const addEmail = gql`
mutation createUser($data: UserCreateInput!) {
createUser(data: $data) {
id
email
}
}
`;
export const addPassword = gql`
mutation updateUser($data: UserUpdateInput!, $where: UserWhereUniqueInput!) {
updateStukentUser(data: $data, where: $where) {
id
password
}
}
`;

Now we can connect the gql queries to our React components. Similar to what react-redux connect function, we use graphql as our connector.

In my route called Emails, I’ve set up my component like so:

//Emails.js
import React from "react";
import { Mutation, graphql } from "react-apollo";
import { getEmails } from "../query.js";
import { addEmail } from "../mutation.js";
class Email extends React.Component {
constructor(props) {
super(props);
this.state = {
email: ""
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
   handleChange(e) {
const { name, value } = e.target;
this.setState({
[name]: value
});
}
   handleSubmit(e) {
e.preventDefault();

//Before creating the email, check from the list of emails if that email already exists
//If email does exist, do not add email and return message "Sorry, That Email is already in our system. Please try another email."
      this.props.createUser(this.state.email);
   }
   render() {
return (
<div className="container">
<form onSubmit={this.handleSubmit}>
<label>Please enter your email address:</label>
<input
type="text"
name="email"
value={this.state.email}
pattern="[^ @]*@[^ @]*"
onChange={this.handleChange}
/>
<input type="submit" value="Submit Email" />
</form>
</div>
);
}
}
export default graphql(getEmails, addEmail, { name: "createUser" })(Email);

In my route called Passwords, I’ve set up my component like so:

//Passwords.js
import React from "react";
import { Mutation, graphql } from "react-apollo";
import { getPasswords } from "../query.js";
import { addPassword } from "../mutation.js";
class Email extends React.Component {
constructor(props) {
super(props);
this.state = {
password: ""
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
   handleChange(e) {
const { name, value } = e.target;
this.setState({
[name]: value
});
}
   handleSubmit(e) {
e.preventDefault();

// Query the user with matching email/ID; then update their password
   }
render() {
return (
<div className="container">
<form onSubmit={this.handleSubmit}>
<label>Please enter your email address:</label>
<input
type="password"
name="password"
value={this.state.email}
pattern="^(?=^.{8,}$)(?=[^A-Za-z]*[A-Za-z])(?=[^0-9]*[0-9])(?:([\w\d*?!:;@#$%^&*()_+=`~-])2?(?!\1))+$"
value={this.state.password}
onChange={this.handleChange}
/>
<input type="submit" value="Submit Password" />
</form>
</div>
);
}
}
export default graphql(getPasswords, addPassword, { name: "updateUser" })(Password);

In these components, I’m passing my gql queries by importing them and wrapping them with graphql. For my mutation where I want to create a new user with an email, I’ll have to map its data type name { name: "createUser"}. The same can be done with updating the user by adding a password with { name: "updateUser"}.

//Email.js
export default graphql(getEmails, addEmail, { name: "createUser" })(Email);
//Password.js
export default graphql(getPasswords, addPassword, { name: "updateUser" })(Password);

After setting up my components, I was ready to begin. I entered an email to the form and clicked submit. Then I received the following errors:

route => /email
// Errors
Network error: Response not successful: Received status code 500
// Console
""
[Object]
....
message: "Variable "$data" of required type "UserCreateInput!" was not provided."

At this point is where I pressed “Paused” on this challenge. After days of a crash course learning of GraphQL and React Apollo, I got stuck on how to submit my inputs. Am I not passing in a variable or props where they should be applied? Did I not set up my queries and mutations properly? How can I pass my input values of this.state.email into the graphql?

I’ll end this post with a “to be continued” as I’ll be tackling this problem later. I had to take a break from GraphQL. Perhaps someone can lead me in the right direction.