▄██████▄ ▄████████ ▄████████ ▄███████▄ ▄█ █▄ ████████▄ ▄█ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ █▀ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ▄███ ▄███▄▄▄▄██▀ ███ ███ ███ ███ ▄███▄▄▄▄███▄▄ ███ ███ ███ ▀▀███ ████▄ ▀▀███▀▀▀▀▀ ▀███████████ ▀█████████▀ ▀▀███▀▀▀▀███▀ ███ ███ ███ ███ ███ ▀███████████ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ▀ ███ ███▌ ▄ ████████▀ ███ ███ ███ █▀ ▄████▀ ███ █▀ ▀██████▀▄█ █████▄▄██ ███ ███ ▀

A GraphQL server implementation for Ruby

Schema — Types and Fields

Types, fields and arguments make up a schema’s type system. These objects are also open to extension via metadata and accepts_definitions.


Types describe objects and values in a system. The API documentation for each type contains a detailed description with examples.

Objects are described with GraphQL::ObjectTypes.

Scalar values are described with built-in scalars (string, int, float, boolean, ID) or custom GraphQL::EnumTypes. You can define custom GraphQL::ScalarTypes, too.

Scalars and enums can be sent to GraphQL as inputs. For complex inputs (key-value pairs), use GraphQL::InputObjectType.

There are two abstract types, too:

  • GraphQL::InterfaceType describes a collection of object types which implement some of the same fields.
  • GraphQL::UnionType describes a collection of object types which may appear in the same place in the schema (ie, may be returned by the same field.)

GraphQL::ListType and GraphQL::NonNullType modify other types, describing them as “list of T” or “required T”.

Referencing Types

Some parts of schema definition take types as an input. There are two good ways to provide types:

  1. By value. Pass a variable which holds the type.

    # constant
    field :team, TeamType
    # local variable
    field :stadium, stadium_type
  2. By proc, which will be lazy-evaluated to look up a type.

    field :team, -> { TeamType }
    field :stadium, -> { LookupTypeForModel.lookup(Stadium) }


GraphQL::ObjectTypes and GraphQL::InterfaceTypes may expose their values with fields. A field definition looks like this:

PostType = GraphQL::ObjectType.define do
  # ...
  #     name  , type        , description (optional)
  field :title, types.String, "The title of the Post"

By default, fields are resolved by sending the name to the underlying object (eg post.title in the example above).

You can define a different resolution by providing a resolve function:

PostType = GraphQL::ObjectType.define do
  # ...
  #     name   , type        , description (optional)
  field :teaser, types.String, "The teaser of the Post" do
    # how to get the value?
    resolve ->(obj, args, ctx) {
      # first 40 chars of the body
      obj.body[0, 40]

The resolve function receives inputs:

In fact, the field do ... end block is passed to GraphQL::Field’s .define method, so you can define many things there:

field do
  name "teaser"
  type types.String
  description "..."
  resolve ->(obj, args, ctx) { ... }
  deprecation_reason "Too long, use .title instead"
  complexity 2


Fields can take arguments as input. These can be used to determine the return value (eg, filtering search results) or to modify the application state (eg, updating the database in MutationType).

Arguments are defined with the argument helper:

field :search_posts, types[PostType] do
  argument :category, types.String
  resolve ->(obj, args, ctx) {
    # => maybe a string, eg "Programming"
    if args[:category]
      Post.where(category: category).limit(10)

Use ! to mark an argument as required:

# This argument is a required string:
argument :category, !types.String

Use as: :alternateName to use a different key from within your resolvers while exposing another key to clients.

field :post, PostType do
  argument :postId, types.Id, as: :id
  resolve ->(obj, args, ctx) {

Only certain types are valid for arguments:

The args parameter of a resolve function will always be a GraphQL::Query::Arguments. You can access specific arguments with ["arg_name"] or [:arg_name]. You recursively turn it into a Ruby Hash with to_h. Inside args, scalars will be parsed into Ruby values and enums will be converted to their value: (if one was provided).

resolve ->(obj, args, ctx) {
  args["category"] == args[:category]
  # => true
  # => { "category" => "Programming" }
  # ...


Registering a mutation root allows to define fields that can mutate your data.

Schema = GraphQL::Schema.define do
  query QueryRoot
  mutation MutationRoot

MutationRoot = GraphQL::ObjectType.define do
  name "Mutation"

  field :addPost, Post do
    description "Adds a Post."

    # Use Input Types to define complex argument types
    argument :post, PostInputType
    resolve ->(t, args, c) {
      title = args['post']['title']
      description = args['post']['description']
      Post.create(title: title, description: description)

PostInputType = GraphQL::InputObjectType.define do
  name "PostInputType"
  description "Properties for creating a Post"

  argument :title, !types.String do
    description "Title of the post."

  argument :description, types.String do
    description "Description of the post."

Extending type and field definitions

Types, fields, and arguments have a metadata hash which accepts values during definition.

First, make a custom definition:

GraphQL::ObjectType.accepts_definitions resolves_to_class_names: GraphQL::Define.assign_metadata_key(:resolves_to_class_names)
# or:
# GraphQL::Field.accepts_definitions(...)
# GraphQL::Argument.accepts_definitions(...)

MySchema = GraphQL::Schema.define do
  # ...

Then, use the custom definition:

Post = GraphQL::ObjectType.define do
  # ...
  resolves_to_class_names ["Post", "StaffUpdate"]

Access type.metadata later:

MySchema = GraphQL::Schema.define do
  # ...
  # Use the type's declared `resolves_to_class_names`
  # to figure out if `obj` is a member of that type
  resolve_type ->(obj, ctx) {
    class_name = obj.class.name
    MySchema.types.values.find { |type| type.metadata[:resolves_to_class_names].include?(class_name) }

This behavior is provided by GraphQL::Define::InstanceDefinable.