GraphQL with React and Apollo Client¶
This section covers how to make GraphQL queries in your react app using the Apollo Client.
Configuration¶
- Install the required dependencies
$ npm install apollo-boost react-apollo graphql --save
- Create an ApolloClient instance and point it to the Hasura Data GraphQL URL via Apollo Link.
import ApolloClient from 'apollo-client';
import { createHttpLink } from 'apollo-link-http';
import { ApolloProvider } from 'react-apollo';
import { InMemoryCache } from 'apollo-cache-inmemory';
const GRAPHQL_URL = "https://data.<cluster-name>.hasura-app.io/v1alpha1/graphql"; //Replace <cluster-name> with the name of your cluster
const client = new ApolloClient({
link: createHttpLink({
uri: GRAPHQL_URL,
credentials: 'include' // Include this to send the cookie along with every request
}),
cache: new InMemoryCache({
addTypename: false
})
});
Note
You have to configure addTypename to false in the InMemoryCache constructor.
- Connect the client to your component tree using the
ApolloProvidercomponent. It is important to putApolloProviderabove every component where you need the GraphQL data. For example, it could be before your root component.
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import ApolloClient from 'apollo-client';
import { createHttpLink } from 'apollo-link-http';
import { ApolloProvider } from 'react-apollo';
import { InMemoryCache } from 'apollo-cache-inmemory';
const GRAPHQL_URL = "https://data.<cluster-name>.hasura-app.io/v1alpha1/graphql"; //Replace <cluster-name> with the name of your cluster
const client = new ApolloClient({
link: createHttpLink({
uri: GRAPHQL_URL,
credentials: 'include' // Include this to send the cookie along with every request
}),
cache: new InMemoryCache({
addTypename: false
})
});
ReactDOM.render(
<ApolloProvider client={client}>
<App />
</ApolloProvider>,
document.getElementById('root')
);
That’s it. You can now make queries and mutations in all the children components.
Exploring the GraphQL queries¶
We will use a simple TODO-list schema for demonstrating the queries.
Table Name: todos
| Column | Type |
|---|---|
| id | serial NOT NULL primary key |
| task | text NOT NULL |
| completed | bool NOT NULL |
| user_id | int NOT NULL |
Querying for data¶
The graphql query to fetch all the todos from the todos table will be:
const QUERY_TODO = gql`
query fetch_todos {
todos {
id
task
completed
}
}
`;
todos above is the name of the table. This is the convention followed by Hasura for GraphQL queries.
Mutations¶
To insert a row into a table, in this case, the todos table, the GraphQL mutation will be:
const MUTATION_TODO_ADD = gql`
mutation insertTodoMutation ($objects: [todos_input]){
insert_todos(objects: $objects) {
affected_rows
returning {
id
task
completed
}
}
}
`;
There are a few things to be noted here:
insert_todosis a convention when inserting data into a table. It is of typeinsert_<TABLE_NAME>, where <TABLE_NAME> is to be replaced with the name of the table to which data is being inserted.- You can insert more than one row at a time. Denoted by
$objects: [todos_input]. todos_inputis the type of the data that will be inserted into the table. The convention followed is<TABLE_NAME>_inputwhere <TABLE_NAME> is to be replaced with the name of the table to which data is being inserted.affected_rowsis the number of rows that were inserted.- The
returningkey specifies the data you want returned after a successful insertion. In this case, we are asking for theid,taskandcompletedcolumns.
To update a row in the table, the mutation looks like:
const MUTATION_TODO_UPDATE = gql`
mutation updateTodoMutation ($todoId: Int, $set: todos_input) {
update_todos(where: {id: {_eq: $todoId}} _set: $set) {
affected_rows
}
}
`;
Things to be noted:
update_todosis a convention when updating data in a table. It is of typeupdate_<TABLE_NAME>, where <TABLE_NAME> is to be replaced with the name of the table where you want to update data.$todoIdis the id of the row that needs to be updated and is of typeInt.$setis the object that this mutation expects, in this case, it should be of typetodos_input. The convention is the same as the one for the insert mutation.where: {id: {_eq: $todoId}}checks that theidof the row that is being updated is the same as the value of$todoIdwhich will be passed as a variable to this mutation.- The
returningkey is optional. You need not specify it, unless you want the data returned after the mutation.
To delete a row in the table, the mutation looks like:
const MUTATION_TODO_DELETE = gql`
mutation deleteTodoMutation ($todoId: Int) {
delete_todos(where: {id: {_eq: $todoId}}) {
affected_rows
}
}
`;
The query is very similar to the update mutation, the only difference is that the convention to delete data from a table is delete_<TABLE_NAME> where <TABLE_NAME> is to be replaced with the name of the table where you want to delete data.