Object fields expose data about that object or connect the object to other objects. You can add fields to your object types with the field(...)
class method, for example:
field :name, String, "The unique name of this list", null: false
Objects%20and%20%20%5BInterfaces%5D(/type_definitions/interfaces) have fields.
The different elements of field definition are addressed below:
The second argument to field(...)
is the return type. This can be:
Integer
, Float
, String
, ID
, or Boolean
)Nullability is expressed with the required null:
keyword:
null: true
means that the field may return nil
null: false
means the field is non-nullable; it may not return nil
. If the implementation returns nil
, GraphQL-Ruby will return an error to the client.Additionally, list types maybe nullable by adding [..., null: true]
to the definition.
Here are some examples:
field :name, String, null: true # `String`, may return a `String` or `nil`
field :id, ID, null: false # `ID!`, always returns an `ID`, never `nil`
field :teammates, [Types::User], null: false # `[User!]!`, always returns a list containing `User`s
field :scores, [Integer, null: true], null: true # `[Int]`, may return a list or `nil`, the list may contain a mix of `Integer`s and `nil`s
Fields maybe documented with a description and may be deprecated.
Descriptions can be added with the field(...)
method as a positional argument, a keyword argument, or inside the block:
# 3rd positional argument
field :name, String, "The name of this thing", null: false
# `description:` keyword
field :name, String, null: false,
description: "The name of this thing"
# inside the block
field :name, String, null: false do
description "The name of this thing"
end
Deprecated fields can be marked by adding a deprecation_reason:
keyword argument:
field :email, String, null: true,
deprecation_reason: "Users may have multiple emails, use `User.emails` instead."
Fields with a deprecation_reason:
will appear as “deprecated” in GraphiQL.
In general, fields return Ruby values corresponding to their GraphQL return types. For example, a field with the return type String
should return a Ruby string, and a field with the return type [User!]!
should return a Ruby array with zero or more User
objects in it.
By default, fields return values by:
Hash
, lookup a key in that hash.The method name or hash key corresponds to the field name, so in this example:
field :top_score, Integer, null: false
The default behavior is to look for a #top_score
method, or lookup a Hash
key, :top_score
(symbol) or "top_score"
(string).
You can override the method name with the method:
keyword, or override the hash key with the hash_key:
keyword, for example:
# Use the `#best_score` method to resolve this field
field :top_score, Integer, null: false,
method: :best_score
# Lookup `hash["allPlayers"]` to resolve this field
field :players, [User], null: false,
hash_key: "allPlayers"
To pass-through the underlying object without calling a method on it, you can use method: :itself
:
field :player, User, null: false,
method: :itself
This is equivalent to:
field :player, User, null: false
def player
object
end
If you don’t want to delegate to the underlying object, you can define a method for each field:
# Use the custom method below to resolve this field
field :total_games_played, Integer, null: false
def total_games_played
object.games.count
end
Inside the method, you can access some helper methods:
object
is the underlying application object (formerly obj
to resolve functions)context
is the query context (passed as context:
when executing queries, formerly ctx
to resolve functions)Additionally, when you define arguments (see below), they’re passed to the method definition, for example:
# Call the custom method with incoming arguments
field :current_winning_streak, Integer, null: false do
argument :include_ties, Boolean, required: false, default_value: false
end
def current_winning_streak(include_ties:)
# Business logic goes here
end
As the examples above show, by default the custom method name must match the field name. If you want to use a different custom method, the resolver_method
option is available:
# Use the custom method with a non-default name below to resolve this field
field :total_games_played, Integer, null: false, resolver_method: :games_played
def games_played
object.games.count
end
resolver_method
has two main use cases:
context
or object
)Note that resolver_method
cannot be used in combination with method
or hash_key
.
Arguments allow fields to take input to their resolution. For example:
search()
field may take a term:
argument, which is the query to use for searching, eg search(term: "GraphQL")
user()
field may take an id:
argument, which specifies which user to find, eg user(id: 1)
attachments()
field may take a type:
argument, which filters the result by file type, eg attachments(type: PHOTO)
Read more in the Arguments guide
Inside a field method, you can access some low-level objects from the GraphQL-Ruby runtime. Be warned, these APIs are subject to change, so check the changelog when updating.
A few extras
are available:
ast_node
graphql_name
(the field’s name)owner
(the type that this field belongs to)lookahead
(see Lookahead)execution_errors
, whose #add(err_or_msg)
method should be used for adding errorsTo inject them into your field method, first, add the extras:
option to the field definition:
field :my_field, String, null: false, extras: [:ast_node]
Then add ast_node:
keyword to the method signature:
def my_field(ast_node:)
# ...
end
At runtime, the requested runtime object will be passed to the field.
Custom extras are also possible. Any method on your field class can be passed to extras: [...]
, and the value will be injected into the method. For example, extras: [:owner]
will inject the object type who owns the field. Any new methods on your custom field class may be used, too.
The field method requires you to pass null:
keyword argument to determine whether the field is nullable or not. For another field you may want to override camelize
, which is true
by default. You can override this behavior by adding a custom field with overwritten camelize
option, which is true
by default.
class CustomField < GraphQL::Schema::Field
# Add `null: false` and `camelize: false` which provide default values
# in case the caller doesn't pass anything for those arguments.
# **kwargs is a catch-all that will get everything else
def initialize(*args, null: false, camelize: false, **kwargs, &block)
# Then, call super _without_ any args, where Ruby will take
# _all_ the args originally passed to this method and pass it to the super method.
super
end
end