GraphQL Cheatsheet



This GraphQL cheatsheet provides a concise reference to key GraphQL concepts, including queries, mutations, schemas, resolvers, and advanced topics like subscriptions, authentication, and performance optimization. It is designed to help developers quickly understand and apply GraphQL's flexible querying capabilities and efficient data fetching mechanisms. Use this guide as a fast resource for building robust and scalable APIs with GraphQL.

Table of Contents

Overview

GraphQL is a query language for APIs that enables clients to request only the data they need. It provides a flexible and efficient alternative to REST APIs by allowing nested queries and reducing the need for multiple endpoints. Tools like GraphiQL help developers execute queries and explore the API schema.

Key Features:

  • Clients fetch only the required fields.
  • Supports nested queries for complex relations.
  • Reduces the need for multiple endpoints.
  • Tools like GraphiQL help execute queries and provide documentation.

Core Concepts

Fundamental elements of GraphQL that define how data is structured, queried, and modified.

  • Query: Fetch data.
  • Mutation: Modify data.
  • Schema: Defines data structure between client and server.
  • Resolvers: Handle data fetching logic.

Basic GraphQL Query Syntax

Queries structure and format used to retrieve data in GraphQL.

Simple Query: Fetches specific user details using a straightforward query format.

query {
  user(id: "1") {
    id
    name
    age
  }
}

Query with Relations: Retrieves user details along with related company information in a single request.

query {
  user(id: "1") {
    id
    name
    company {
      id
      name
    }
  }
}

Parameterized Queries: Uses variables to fetch dynamic data based on input parameters.

query UserQuery($id: ID!) {
  user(id: $id) {
    id
    name
  }
}

Variables: Defines values for parameters in queries to improve reusability.

{
  "id": "1"
}

Mutations

Mutations are GraphQL operations that enable data creation, modification, and deletion.

Example:

mutation {
  addUser(name: "Alice", age: 25) {
    id
    name
  }
}

Parameterized Mutation: Uses variables to dynamically update user details.

mutation UpdateUser($id: ID!, $name: String) {
  updateUser(id: $id, name: $name) {
    id
    name
  }
}

Variables: Provides structured input values for mutation execution.

{
  "id": "1",
  "name": "Bob"
}

GraphQL Schema

Schema defines the structure, types, and relationships within a GraphQL API.

Basic Example:

type Query {
  user(id: ID!): User
  company(id: ID!): Company
}

type Mutation {
  addUser(name: String!, age: Int!): User
}

type User {
  id: ID!
  name: String
  age: Int
  company: Company
}

type Company {
  id: ID!
  name: String
  users: [User]
}

Built-in Scalar Types:

Includes Int, Float, String, Boolean, and ID for structured data representation.

  • Int: A signed 32bit integer.
  • Float: A signed double-precision floating-point value.
  • String: A UTF8 character sequence.
  • Boolean: true or false.
  • ID: A unique identifier.

Type Modifiers: 

Defines nullable, non-nullable, and list types to enforce data integrity.

  • String: Nullable.
  • String!: Non-nullable.
  • [String]: List of strings.
  • [String]!: Required list.
  • [String!]!: Required list of required strings.

Resolvers

Resolvers are the functions that handle GraphQL queries and return appropriate responses from the data source.

Resolvers define how fields fetch data: An example of a resolver function that retrieves and modifies user data based on client requests.

const resolvers = {
  Query: {
    user(parent, args) {
      return users.find(user => user.id === args.id);
    },
  },
  Mutation: {
    addUser(parent, args) {
      const newUser = { id: generateId(), ...args };
      users.push(newUser);
      return newUser;
    },
  },
};

GraphQL Client

Libraries that simplify the process of interacting with GraphQL APIs from the client side.

  • Lokka: Lightweight, basic features.
  • Apollo Client: Feature-rich and developer-friendly.
  • Relay: High-performance, but complex.

Apollo Client Setup

Setting up Apollo Client for seamless GraphQL API interaction.

Initialization: Configures Apollo Client by specifying the GraphQL API endpoint.

import ApolloClient from 'apollo-client';
const client = new ApolloClient({
  uri: '/graphql',
});

Query Example: Demonstrates how to fetch data from a GraphQL API using Apollo Client.

import gql from 'graphql-tag';
const query = gql`
  query {
    user(id: "1") {
      id
      name
    }
  }
`;

Mutation Example: This shows how to modify data using a GraphQL mutation in Apollo.

const mutation = gql`
  mutation AddUser($name: String!, $age: Int!) {
    addUser(name: $name, age: $age) {
      id
      name
    }
  }
`;

Advanced GraphQL

Enhancing GraphQL capabilities with additional features like fragments, aliases, and interfaces.

Fragments: Reusable query components that avoid redundancy and improve efficiency.

fragment userFields on User {
  id
  name
  age
}

query {
  user(id: "1") {
    ...userFields
  }
}

Aliases: Assigns custom names to query responses to differentiate between similar data structures.

{
  alice: user(id: "1") {
    name
  }
  bob: user(id: "2") {
    name
  }
}

Interfaces: Defines shared fields across multiple types for better code reuse and type safety.

interface Entity {
  id: ID!
}

type User implements Entity {
  id: ID!
  name: String
}

GraphQL over HTTP

How GraphQL queries and mutations are executed over HTTP requests.

GET: Sends queries via URL parameters for simple data retrieval.

fetch('/graphql?query={ user { id name } }');

POST: Sends queries and mutations in the request body for more complex operations.

fetch('/graphql', {
  method: 'POST',
  body: JSON.stringify({
    query: `query { user(id: "1") { id name } }`,
  }),
});

Subscriptions

Enables real-time updates using GraphQL by listening to specific data changes.

Type Description Code Example
Basic Subscription Defines a simple subscription to listen for an event.

subscription { event { field } }

Subscription with Variables Uses input variables for dynamic event filtering.

subscription ($input: InputType) { event(input: $input) { field } }

Input Type Defines the structure of the input variable used in the subscription.

input InputType { field: String }

Trigger Event The server triggers an event (e.g., like/unlike) using PubSub or WebSockets.

// Handled in backend logic

Example Subscription Listens for new likes on a story.

subscription StoryLike($input: Input) { storyLike(input: $input) { likers { count } } }

Authentication & Authorization

Ensuring secure access control in GraphQL APIs using tokens and role-based restrictions.

Authentication Setup

Extract the Token from Headers: Extracts and verifies user authentication tokens from request headers.

context: async ({ req }) => {
  const token = req.headers.authorization || '';
  const user = await getUser(token); // Fetch user info using token
  return { user };
};

Deny Unauthenticated Users: Prevents access to GraphQL operations without valid authentication.

if (!user) {
  throw new GraphQLError('User is not authenticated', {
    extensions: { code: 'UNAUTHENTICATED', http: { status: 401 } },
  });
}

Authorization Techniques

Resolver-based Authorization: Implements role-based access control at the resolver level.

users: (parent, args, contextValue) => {
  if (!contextValue.user || !contextValue.user.roles.includes('admin')) return null;
  return contextValue.models.User.getAll();
};

API-wide Authorization: API access globally based on authentication status.

context: async ({ req }) => { 
  const user = getUser(req.headers.authorization);
  if (!user) throw new GraphQLError('Unauthenticated');
  return { user };
};

Using Models for Access Control: Validates permissions before allowing data retrieval.

export const generateUserModel = ({ user }) => ({
  getAll: () => {
    if (!user || !user.roles.includes('admin')) return null;
    return fetch('http://example.com/users');
  },
}); 

Custom Directive Authorization

Define a Schema Directive: Uses schema directives to enforce authorization rules.

directive @auth(requires: Role = ADMIN) on OBJECT | FIELD_DEFINITION

enum Role {
  ADMIN
  REVIEWER
  USER
}

type User @auth(requires: USER) {
  name: String
  banned: Boolean @auth(requires: ADMIN)
  canPost: Boolean @auth(requires: REVIEWER)
}

Error Handling

Handling, formatting, and reporting errors in GraphQL APIs.

Aspect Description Example/Error Code
Error Response Errors are listed in the errors array. GRAPHQL_PARSE_FAILED
Built-in Error Codes Predefined common error codes. INTERNAL_SERVER_ERROR
Custom Errors Define errors with GraphQLError. FORBIDDEN, UNAUTHENTICATED
FormatError Hook Customize error messages. Change GRAPHQL_VALIDATION_FAILED.
Masking Errors Hide sensitive error details. Mask API keys or stacktraces.
Error Reporting Filter/report errors to Apollo Studio. Ignore minor errors.
HTTP Status Codes Modify HTTP status in responses. Set 404 for specific cases.
Logging Errors Log errors; hide stacktrace in production. Disable stacktrace in production.
Usage Reporting Adjust error details before reporting. Remove PII from errors.

Filtering, Pagination & Sorting

Efficient data retrieval techniques using filters, pagination, and sorting.

Feature Description Query Code
Filtering Filter Link items by description or URL. feed(filter: String): [Link!]!
Pagination Use skip (start index) and take (limit) for pagination. feed(filter: String, skip: Int, take: Int): [Link!]!
Sorting Sort links by description, URL, or createdAt in ascending (asc) or descending (desc) order.
input LinkOrderByInput {
  description: Sort
  url: Sort
  createdAt: Sort
}
enum Sort {
  asc
  desc
}
feed(orderBy: LinkOrderByInput): [Link!]!
Count Links Return the total count of Link items along with filtered/sorted links.
type Feed {
  links: [Link!]!
  count: Int!
}
feed: Feed!

Directives

Special annotations that modify GraphQL query behavior dynamically.

Directive Explanation Example
@deprecated Marks a field or enum value as outdated with an optional reason. field: String @deprecated(reason: "Use `newField`.")
@skip Excludes a field/fragment if the condition is true. query { field @skip(if: true) }
@include Includes a field/fragment only if the condition is true. query { field @include(if: true) }
Custom Directive Adds custom logic to schema or operations. directive @uppercase on FIELD_DEFINITION type Query { field: String @uppercase }
Directive Locations Specifies valid placements (e.g., fields, arguments, enums). directive @example on FIELD_DEFINITION

Performance Optimization

Techniques to improve GraphQL API performance and reduce redundant queries.

Technique Description Code Example
Cache Redirection Resolve data from the cache using custom resolvers. cacheRedirects: { Query: { book: (_, args) => toIdValue({ __typename: 'Book', id: args.id }) } }
Prefetching Data Load data into the cache before it's needed. client.query({ query: GET_DOG, variables: { breed: data.breed } });
Query Splitting Split large queries into cached and server queries. QUERY 1: { id title } QUERY 2: { id episodes { id title } }
Custom Resolvers Map queries to cached data. cacheResolvers: { Query: { oneSeries: (_, { id }) => toIdValue({ __typename: 'Series', id }) } }
Fragments Reuse query parts to avoid over-fetching. fragment EpisodeDetails on Episode { id title cover }
Advertisements