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
The different elements of field definition are addressed below:
The second argument to
field(...) is the return type. This can be:
Nullability is expressed with the required
null: truemeans that the field may return
null: falsemeans 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
:top_score (symbol) or
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
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:
objectis the underlying application object (formerly
objto resolve functions)
contextis the query context (passed as
context:when executing queries, formerly
ctxto 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:
resolver_method cannot be used in combination with
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
user()field may take an
id:argument, which specifies which user to find, eg
attachments()field may take a
type:argument, which filters the result by file type, eg
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.
extras are available:
graphql_name(the field’s name)
owner(the type that this field belongs to)
#add(err_or_msg)method should be used for adding errors
argument_details(Intepreter only), an instance of
GraphQL::Execution::Interpreter::Argumentswith argument metadata
To inject them into your field method, first, add the
extras: option to the field definition:
field :my_field, String, null: false, extras: [:ast_node]
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