I'm in the process of building a GraphQL API in a Rails 7 application, using the graphql-ruby
gem.
In the app, users can create lists of catalogue items, and their lists can be manually ordered. So the simplified ActiveRecords look a bit like this:
class List < ApplicationRecord
has_many :list_items
has_many :items, through: :list_items
end
class ListItem < ApplicationRecord
belongs_to :list
belongs_to :item
# attributes include :position, :updated_at, etc.
end
class Item < ApplicationRecord
has_many :list_items
has_many :lists, through: :list_items
end
What I'd like to be able to do is to include the ListItem's attributes within the edge of the response, e.g.:
list(id: $id) {
title
createdAt
items {
edges {
position
updatedAt
node {
id
title
thumbnailUrl
}
}
}
}
I've tried creating custom Connection
and Edge
objects, but have so far failed to work out how to express that the edge has a direct ActiveRecord equivalence to a particular ListItem
record such that I can retrieve the necessary attributes.
So I think I've cracked it.
In my ListType
I declare my custom connection:
module Types
class ListType < Types::BaseObject
field :id, ID, null: false
field :title, String, null: false
field :items, Types::ListItemConnectionType, connection: true
def items
object.list_items.order(:position)
end
end
end
The connection inherits from my base connection type but specifies the custom edge type:
module Types
class ListItemConnectionType < Types::BaseConnection
edge_type Types::ListItemEdgeType
end
end
In the edge type, object.node
is the ListItem
record - so we need to provide a custom node
method to expose its associated Item
module Types
class ListItemEdgeType < Types::BaseEdge
node_type(Types::ItemType)
field :position, Integer
field :updated_at, GraphQL::Types::ISO9601DateTime
def position
object.node.position
end
def updated_at
object.node.updated_at
end
def node
object.node.item
end
end
end
If anybody has an alternative approach, I'd love to hear it.