To create graphql model, you need to include ActiveGraphql::Model
module in your ruby class like this:
class User
include ActiveGraphql::Model
active_graphql do |c|
c.url 'http://localhost:3000'
c.attributes :id, :first_name, :last_name
end
end
Attributes also can be nested, like this:
class User
include ActiveGraphql::Model
active_graphql do |c|
c.attributes location: [:city, :country, :street]
end
end
User.find(3).location # { city: 'London', country: ... }
Sets url where all GraphQL queries should go
class User
include ActiveGraphql::Model
active_graphql do |c|
c.url 'http://localhost:3000'
end
end
Sets attributes which can be fetched from graphql
class User
include ActiveGraphql::Model
active_graphql do |c|
c.attributes :id, :first_name, :last_name
end
end
User.find(3).first_name # => some name returned from graphql
Sets attribute which can be fetched from graphql
class User
include ActiveGraphql::Model
active_graphql do |c|
c.attribute :name
end
end
User.find(3).name # => "John"
You can have nested attributes. Nested values will be returned as hash:
class User
include ActiveGraphql::Model
active_graphql do |c|
c.attribute :id
c.attribute :location, [:lat, :long]
end
end
User.find(3).location #=> { lat: 25.0, long: 26.0 }
You can use decorator methods in order to modify model attribute values. It's very in combination with nested values
class User
include ActiveGraphql::Model
active_graphql do |c|
c.attribute :name, decorate_with: :make_fancy_name
end
def make_fancy_name(original_name)
"Mr. #{original_name}"
end
end
User.find(3).name #=> "Mr. John"
Sets attributes which can be fetched from graphql
class User
include ActiveGraphql::Model
active_graphql do |c|
c.resource_name :admin_user
c.attributes :id
end
end
User.where(name: 'John').to_graphql # => "query { adminUsers(name: "John") { id } }"
By default primary key is id
, but you can change it like this:
class User
include ActiveGraphql::Model
active_graphql do |c|
c.primary_key :email
end
end
User.find('[email protected]') # will execute in GraphQL: 'query { user(email: "[email protected]") }'
Use find
method in order to find record:
user = User.find(5)
Use update
to update record on graphql side:
User.find(5).update(first_name: 'John') # => true or false
Use update!
to update record on graphql side:
User.find(5).update!(first_name: 'John') # => true or exception
Use destroy
in order to delete record on graphql side:
User.find(5).destroy # => true or false
to create model on graphql side simply use create
method, like this:
user = User.create(first_name: 'John', last_name: 'Doe')
as in ActiveRecord, there is create!
method which will raise error when create fails:
user = User.create!(first_name: 'John', last_name: 'Doe')
Use where
method in order to find multiple record:
users = User.where(name: 'John')
Use merge
method in order to merge multiple queries:
# same as User.where(name: 'John', surname: 'Doe') :
users = User.where(name: 'John').merge(User.where(surname: 'Doe'))
Use or
method in order to query using "or" predicate:
# same as User.where(or: { name: 'John', surname: 'Doe' }) :
users = User.where(name: 'John').or(User.where(surname: 'Doe'))
Keep in mind that your endpoint must support filtering by "or" key like this:
query {
users(filter: { or: { name: 'John', surname: 'Doe' } }) {
...
}
}
Use order
when you need to sort results:
users.order(created_at: :desc)
In order to iterate through multiple pages, you need to use find_each
method
User.all.find_each do |user|
do_something(user)
end
you can also paginate records:
User.paginate(page: 1, per_page: 3)
you can also paginate records:
User.page(1)
You can select only attributes which you want to be selected from model, like this:
class User
include ActiveGraphql::Model
active_graphql do |c|
c.url 'http://example.com/graphql'
c.attributes :id, :first_name, location: %i[street city], name: :full_name
end
def self.main_data
select(:first_name, location: :city, name: :full_name)
end
end
User.main_data
This will produce GraphQL:
query {
users {
firstName
location {
city
}
name {
fullName
}
}
}
You can define your custom queries by adding class method, like this:
class User
include ActiveGraphql::Model
active_graphql do |c|
c.attributes :id
end
def self.with_custom
where(custom: true)
end
end
User.where(id: 1).with_custom
this will produce GraphQL:
query {
users(filter: { id: 1, custom: true } ) {
id
}
}
You can define your custom mutations by adding instance method, like this:
class User
include ActiveGraphql::Model
active_graphql do |c|
c.attributes :id, :first_name, :last_name
end
def update_name(first_name, last_name)
mutate(:update_name, input: { first_name: 'Fancy', last_name: 'Pants' })
end
end
User.last.update_name('Fancy', 'Pants')
This will produce GraphQL:
mutation {
updateName(id: 99, input: { firstName: 'Fancy', lastName: 'Pants' }) {
id
firstName
lastName
...
}
}
In order to make active_graphql work, server must met some conditions.
Resource, attribute and field names must be in camelcase
Let's say we have BlogPost
resource, so CRUD actions should be named like this:
blogPost(id: ID!)
(aka,show
action)blogPosts(filter: FilterInput)
(aka,index
action)createBlogPost(input: SomeCreateInput!)
(aka,create
action)updateBlogPost(id: ID!, input: SomeUpdateInput!)
(aka,update
action)destroyBlogPost(id: ID!)
(aka,destroy
action)
In order to make Model#find work, server must have resource in singular form with single id: ID!
argument.
Example: user(id: ID!)
In order to make Model#all and Model#find_each work, server must have resource in plural form and also response should be paginated.
Example:
users(first: Integer, last: Integer, before: String, after: String) {
edges {
node {
...
}
}
}
In order to make Model#where and Model#find_by work, server must have resource in plural form with filter: SomeFilterInput
argument. Also resource must match requirements for Model#all too (see previous section)
Example:
type UsersFilterInput {
firstName: String!
lastName: String!
}
users(filter: UserFilterInput) {
edges {
node {
...
}
}
}
In order to make Model#or resouce must match requirements for Model#where
method. Also filter
input must have or
argument
Example:
type UsersFilterInput {
or: UsersOrFilterInput
groupId: [ID!],
name: String!
}
type UsersOrFilterInput {
groupId: [ID!],
name: String!
}
users(filter: UserFilterInput) {
edges {
node {
...
}
}
}
In order to make Model#where and Model#find_by work, server must have resource in plural form. This resource must have total:Integer
output field:
Example:
users() {
total
edges {
node {
...
}
}
}