Table of Contents
GraphQL Cheat Sheet
Overview
- An alternative approach to RESTful APIs
- Clients issue queries/mutations to read and update data
- Clients can fetch only the entity fields that are required
- GraphQL query syntax can express complex entity relations => nested objects
- Mitigates the explosion of RESTful endpoints in scenarios where many different representations of an entity are needed
- Graphiql is a query execution UI, also provides good documentation
Express Server Integration
const express = require('express');const expressGraphQL = require('express-graphql');const schema = require('./schema/schema');// create express appconst app = express();app.use('/graphql', expressGraphQL({schema,graphiql: true}));// register app to listen on a portapp.listen(4000, () => {console.log('Server started!');});
Schema Types
- GraphQL Schema types define the data contract between the client and the server
const GraphQL = require('graphql');const {GraphQLObjectType,GraphQLString,GraphQLInt,GraphQLList,GraphQLSchema,GraphQLNonNull} = GraphQL;// define the company schema typeconst CompanyType = new GraphQLObjectType({name: 'Company',// use a closure to work around cyclical referencesfields: () => ({id: { type: GraphQLString },name: { type: GraphQLString },description: { type: GraphQLString },users: {type: new GraphQLList(UserType),resolve(parentValue, args){return axios.get(`http://localhost:3000/companies/${parentValue.id}/users`).then(resp => resp.data);}}})});// define the user schema typeconst UserType = new GraphQLObjectType({name: 'User',// use a closure to work around cyclical referencesfields: () => ({id: { type: GraphQLString },firstName: { type: GraphQLString },age: { type: GraphQLInt },company: {type: CompanyType,resolve(parentValue, args) {return axios.get(`http://localhost:3000/companies/${parentValue.companyId}`).then(resp => resp.data);}}})});
Root Query Type
const RootQuery = new GraphQLObjectType({name: 'RootQueryType',fields: {user: {type: UserType,args: { id: { type: GraphQLString }},resolve(parentValue, args) {return [];}},company: {type: CompanyType,args: { id: { type: GraphQLString }},resolve(parentValue, args) {// async promisereturn axios.get(`http://localhost:3000/companies/${args.id}`).then(resp => resp.data);}}}});
Root Mutation Type
const Mutation = new GraphQLObjectType({name: 'Mutation',fields: {addUser: {type: UserType,args: {firstName: { type: new GraphQLNonNull(GraphQLString) },age: { type: new GraphQLNonNull(GraphQLInt) },companyId: { type: GraphQLString }},resolve(parentValue, { firstName, age }) {return axios.post(`http://localhost:3000/users`, {firstName,age}).then(res => res.data);}},editUser: {type: UserType,args: {id: { type: new GraphQLNonNull(GraphQLString) },firstName: { type: GraphQLString },age: { type: GraphQLInt },companyId: { type: GraphQLString }},resolve(parentValue, { id, firstName, age, companyId }) {var updatedUser = { firstName, age, companyId };return axios.patch(`http://localhost:3000/users/${id}`, updatedUser).then(res => res.data);}}}});
GraphQL Query Syntax
Simple Query:
query {user(id: "40"){idfirstNameage}}
Query With Relations:
query {user(id: "40"){idfirstNameagecompany {id,name,description}}}
Query Fragments:
query findCompanyUsers {apple: company(id:"1"){...companyDetails}google: company(id:"2"){...companyDetails}}fragment companyDetails on Company {idnamedescriptionusers {idfirstNameage}}
Parameterized Queries:
query UserQuery($id: ID!){song(id: $id){idfirstName}}
Parameter Values:
{"id": 12345}
Mutation:
mutation {addUser(firstName: "Jeff", age: 34){idfirstNameage}}
GraphQL Clients
- Lokka - Simple implementation: basic queries, mutations, and simple caching
- Apollo Client - Good balance between features and complexity
- Relay - Amazing performance on mobile, but the most complex.
Apollo Client Initialization
Configuring a basic GraphQL client:
// ...import ApolloClient from 'apollo-client';import { ApolloProvider } from 'react-apollo';// tracks objects by the ID fieldconst client = new ApolloClient({dataIdFromObject: object => object.id});const Root = () => {return (<ApolloProvider client={client}><App /></ApolloProvider>);};ReactDOM.render(<Root />,document.querySelector('#root'));
Configuring the GraphQL client network interface:
const networkInterface = createNetworkInterface({uri: '/graphql',opts: {credentials: 'same-origin' // same-origin request, send cookies w/ request}});const client = new ApolloClient({networkInterface,dataIdFromObject: o => o.id});
GraphQL Client Query
Defining a simple GraphQL query:
import gql from 'graphql-tag';export default gql`query {currentUser {id}}`;
Defining a parameterized GraphQL query:
import gql from 'graphql-tag';export default gql`query UserByIdQuery($id: ID!) {user(id: $id){id}}`;
GraphQL Client Mutation
Defining a parameterized GraphQL mutation:
import gql from 'graphql-tag';export default gql`mutation LoginMutation($email: String, $password: String) {login(email: $email, password: $password) {id}}`;
React Components with GraphQL Queries
import React, { Component } from 'react';import gql from 'graphql-tag';class HelloGraphQL extends Component {render(){return (<p>Hello, {this.props.data.name}</p>);}}const currentUser = gql`query {currentUser {idfirstName}}`;// funky syntax, but this binds the query to the component propsexport default graphql(userQuery)(HelloGraphQL);
An alternative syntax:
// ...// this reads a little betterconst withData = graphql(userQuery);export default withData(HelloGraphQL);
React Components with GraphQL Mutations
An example of a basic mutation:
import React, { Component } from 'react';import gql from 'graphql-tag';import ListUsers from '../queries/ListUsers';class MutationExample extends Component {onDeleteUser(){const id = 123;this.props.mutate({ variables: { id } }).then(() => this.props.data.refetch());};}render(){return (<div><button onClick={this.onDeleteUser.bind(this)}>DeleteUser</button</div>);}}const deleteUserMutation = gql`mutation DeleteUser($id: ID){deleteUser(id: $id){id}}`;const withMutation = graphql(deleteUserMutation);export withMutation(MutationExample);
Explicitly refetching GraphQL queries after a mutation:
// explicity reference the ListUsersQuery query for refetchthis.props.mutate({variables: { id },refetchQueries: [ { ListUsersQuery } ]});
React Components with Mutations and Queries
const withData = graphql(listUsersQuery);const withMutation = graphql(deleteUserMutation);export withData(withMutation(UsersList));
React Components with Multiple Mutations
Edit this page on GitHubimport { compose } from 'react-apollo';const ComponentWithMutations = compose(graphql(submitNewUser, { name: 'newUserMutation' }),graphql(submitRepository, { name: 'newRepositoryMutation' }))(Component);