Input object types are complex inputs for GraphQL operations. They’re great for fields that need a lot of structured input, like mutations or search fields. In a GraphQL request, it might look like this:
mutation {
createPost(attributes: { title: "Hello World", fullText: "This is my first post", categories: [GENERAL] }) {
# ^ Here is the input object ..................................................... ^
}
}
Like a Ruby Hash
, an input object consists of keys and values. Unlike a Hash, its keys and value types must be defined statically, as part of the GraphQL system. For example, here’s an input object, expressed in the GraphQL Schema Definition Language (SDL):
input PostAttributes {
title: String!
fullText: String!
categories: [PostCategory!]
}
This input object has three possible keys:
title
is required (denoted by !
), and must be a String
fullText
is also a required Stringcategories
is optional (it doesn’t have !
), and if present, it must be a list of PostCategory
values.Input object types extend GraphQL::Schema::InputObject
and define key-value pairs with the argument(...)
method. For example:
# app/graphql/types/base_input_object.rb
# Add a base class
class Types::BaseInputObject < GraphQL::Schema::InputObject
end
class Types::PostAttributes < Types::BaseInputObject
description "Attributes for creating or updating a blog post"
argument :title, String, "Header for the post", required: true
argument :full_text, String, "Full body of the post", required: true
argument :categories, [Types::PostCategory], required: false
end
For a full description of the argument(...)
method, see the argument section of the Objects guide.
Input objects are passed to field methods as an instance of their definition class. So, inside the field method, you can access any key of the object by:
#[]
with the camel-cased name of the argument (this is for compatibility with previous GraphQL-Ruby versions)# This field takes an argument called `attributes`
# which will be an instance of `PostAttributes`
field :create_post, Types::Post, null: false do
argument :attributes, Types::PostAttributes, required: true
end
def create_post(attributes:)
puts attributes.class.name
# => "Types::PostAttributes"
# Access a value by method (underscore-cased):
puts attributes.full_text
# => "This is my first post"
# Or by hash-style lookup (camel-cased, for compatibility):
puts attributes[:fullText]
# => "This is my first post"
end
You can customize the GraphQL::Schema::Argument
class which is used for input objects:
class Types::BaseArgument < GraphQL::Schema::Argument
# your customization here ...
end
class Types::BaseInputObject < GraphQL::Schema::InputObject
# Hook up the customized argument class
argument_class(Types::BaseArgument)
end
You can also add or override methods on input object classes to customize them. They have two instance variables by default:
@arguments
: A GraphQL::Query::Arguments
instance@context
: The current GraphQL::Query::Context
Any extra methods you define on the class can be used for field resolution, as demonstrated above.
Your input objects can be automatically converted to other Ruby types before they’re passed to your application code. This is an easy way to use Range
’s in your schema:
class Types::DateRangeInput < Types::BaseInputObject
description "Range of dates"
argument :min, Types::Date, "Minimum value of the range", required: true
argument :max, Types::Date, "Maximum value of the range", required: true
def prepare
min..max
end
end
class Types::CalendarType < Types::BaseObject
field :appointments, [Types::Appointment], "Appointments on your calendar", null: false do
argument :during, Types::DateRangeInput, "Only show appointments within this range", required: true
end
def appointments(during:)
# during will be an instance of Range
object.appointments.select { |appointment| during.cover?(appointment.date) }
end
end