Skip to content

Instantly share code, notes, and snippets.

@jbritton
Last active September 24, 2024 21:25
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);
@cc-59
Copy link

cc-59 commented Sep 24, 2024

Copy-pasting everything from Stephen Grider's course about React+Graphql on udemy is not creating an useful cheatsheet.

@jbritton
Copy link
Author

@claudiucs123 Sorry, this was for my own reference. I guess I should've made this gist private.

@cc-59
Copy link

cc-59 commented Sep 24, 2024

Pardon for my comment, if that was your true intention.

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