GraphitiGql
GraphQL bindings for Graphiti.
Write code like this:
class EmployeeResource < ApplicationResource
attribute :first_name, :string
attribute :age, :integer
has_many :positions
end
Get an API like this:
query {
employees(
filter: { firstName: { match: "arha" } },
sort: [{ att: age, dir: desc }],
first: 10,
after: "abc123"
) {
edges {
node {
id
firstName
age
positions {
nodes {
title
}
}
}
cursor
}
stats {
total {
count
}
}
}
}
Getting Started
# Gemfile
gem 'graphiti'
gem "graphiti-rails"
gem 'graphiti_gql'
# config/routes.rb
Rails.application.routes.draw do
scope path: ApplicationResource.endpoint_namespace do
mount GraphitiGql::Engine, at: "/gql"
end
end
Write your Graphiti code as normal, omit controllers.
How does it work?
This autogenerates graphql-ruby
code by introspecting Graphiti Resources. Something like this happens under-the-hood:
field :employees, [EmployeeType], null: false do
argument :filter, EmployeeFilter, required: false
# ... etc ...
end
def employees(**arguments)
EmployeeResource.all(**arguments).to_a
end
In practice it's more complicated, but this is the basic premise - use Graphiti resources to handle query and persistence operations; autogenerate graphql-ruby
code to expose those Resources as an API. This means we play nicely with e.g. telemetry and error-handling libraries because it's all graphql-ruby
under-the-hood...except for actually performing the operations, which is really more a Ruby thing than a GraphQL thing.
Caveats
This rethinks the responsibilities of Graphiti, coupling the execution cycle to graphql-ruby
. We do this so we can play nicely with other gems in the GQL ecosystem, and saves on development time by offloading responsibilities. The downside is we can no longer run a JSON:API
with the same codebase, and certain documentation may be out of date.
Longer-term, we should rip out only the parts of Graphiti we really need and redocument.