Skip to content

Instantly share code, notes, and snippets.

@jbritton
Last active January 4, 2024 21:46
Show Gist options
  • Save jbritton/1f60ef440686b51ee37b708e6376b26e to your computer and use it in GitHub Desktop.
Save jbritton/1f60ef440686b51ee37b708e6376b26e to your computer and use it in GitHub Desktop.
GraphQL Cheat Sheet

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 app
const app = express();
app.use('/graphql', expressGraphQL({
    schema,
    graphiql: true
}));

// register app to listen on a port
app.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 type
const CompanyType = new GraphQLObjectType({
    name: 'Company',
    // use a closure to work around cyclical references
    fields: () => ({
        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 type
const UserType = new GraphQLObjectType({
    name: 'User',
    // use a closure to work around cyclical references
    fields: () => ({
        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 promise
                return 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"){
		id
		firstName
		age
	}
}

Query With Relations:

query {
  user(id: "40"){
    id
    firstName
    age
    company {
        id,
        name,
        description
    }
  }
}

Query Fragments:

query findCompanyUsers {
	apple: company(id:"1"){
		...companyDetails
	}  
	google: company(id:"2"){
		...companyDetails
  	}
}

fragment companyDetails on Company {
    id
    name
    description
    users {
      	id
      	firstName
      	age
    }
}

Parameterized Queries:

query UserQuery($id: ID!){
  song(id: $id){
    id
    firstName
    email
  }
}

Parameter Values:

{
  "id": 12345
}

Mutation:

mutation {
  addUser(firstName: "Jeff", age: 34){
    id
    firstName
    age
  }
}

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 field
const 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
		email
	}
}
`;

Defining a parameterized GraphQL query:

import gql from 'graphql-tag';

export default gql`
query  UserByIdQuery($id: ID!) {
	user(id: $id){
		id
		email
	}
}
`;

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
        email
      }
    }
`;

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 {
	    id
	    firstName
	    email
	  }
	}
`;

// funky syntax, but this binds the query to the component props
export default graphql(userQuery)(HelloGraphQL);

An alternative syntax:

// ...

// this reads a little better
const 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 refetch
this.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

import { compose } from 'react-apollo';

const ComponentWithMutations = compose(
  graphql(submitNewUser, { name: 'newUserMutation' }),
  graphql(submitRepository, { name: 'newRepositoryMutation' })
)(Component);
@richarddewit
Copy link

In "React Components with GraphQL Queries", you have const currentUser = gql, but I think this has to be const userQuery = gql

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment