GraphQL

Write an awesome doc for GraphQL. A very nice an practical one extracted from GraphQL official documentation.

View on GitHub

Execution from inside

Execution flowchart

Resolvers

# A resolver function receives 4 arguments in this specific order:

async function getTodo(
  /**
   * @description
   * The previous object.
   *
   * - AKA root, or parent.
   * - A GraphQL server needs to call the resolvers of a query’s fields. GraphQL does a breadth-first (level-by-level) resolver call. The root argument in each resolver call is simply the result of the previous call.
   * - Mostly won't be used.
   */
  obj,
  /**
   * @description
   * Arguments/parameters passed to a field in a GraphQL operation.
   * @example `getTodo(id: ID!)`
   */
  args: { id: string },
  /**
   * @description
   * An object that every resolver can write to and read from it so that resolvers can communicate.
   *
   * Holds important contextual information, things like:
   * - Access to a database.
   * - The currently logged in user.
   */
  context: { db: PrismaClient },
  /**
   * @description
   * The Abstract Syntax Tree representation of a query or mutation.
   *
   * Holds field-specific* info and the schema details.
   *
   * *Things relevant to the current operation.
   */
  info,
) {
  const todo = await context.db.todo.find({
    where: { id: args.id },
  });
  const graphqlTodoObject = new GraphqlTodo(todo);

  return graphqlTodoObject;
}
class GraphqlTodo {
  public id: string;
  public title: string;
  public content: string;
  public createdAt: Date;
  public updatedAt: Date;
  public CreatedBy: { id: string; username: string };
  public createdById: string;
  public AssignedTo: { id: string; username: string };
  public assignedToId: string;

  constructor(todo: PrismaTodo) {
    this.id = todo.id;
    this.title = todo.title;
    this.content = todo.content;
    this.createdAt = todo.createdAt;
    this.updatedAt = todo.updatedAt;
    this.CreatedBy = todo.CreatedBy;
    this.createdById = todo.createdById;
    this.AssignedTo = todo.AssignedTo;
    this.assignedToId = todo.assignedToId;
  }
}

An Important Note About args in a Resolver

The args parameter is populated by the arguments passed to the field being resolved -- any arguments passed to other fields will not be included in the args parameter.

Ref.

[!NOTE]

I’ve demystified the info object in GraphQL here.

# No Need to Define Trivial Resolvers Like getTodoName

import { GraphQLResolveInfo } from 'graphql';

function getTodoName(
  obj: GraphqlTodo,
  args,
  context,
  info: GraphQLResolveInfo,
) {
  return obj.name;
}

Most of the times when we have not defined a resolver the lib we’re using to build our GraphQL service assume that there is a property/method named exactly the same as the field. Thus it automatically calls that one.

What is AST

Tokenization

A GraphQL Query Parts After Tokenization

tokenized GraphQL query

Ref