Attribute Names
All of the attributes that were using snake case syntax (snake_case) in the ruby models are exposed in the queries/mutations as camel cased (camelCase).
Graphoid depends on the GraphQL implementation for Ruby. To have that gem installed you can visit graphql-ruby to install it or:
gem "graphql"
$ bundle install
$ rails generate graphql:install
You can optionally install GraphQL Playground, a visual client to start querying the server
$ brew cask install graphql-playground
gem "graphoid"
$ bundle install
Graphoid works trasparently with ActiveRecord or Mongoid
Create the configuration file config/initializers/graphoid.rb
Graphoid.configure do |config|
config.driver = :active_record
end
Graphoid.configure do |config|
config.driver = :mongoid
end
By adding the concerns, you can tell graphoid which of your models will be visible in the API.
You can include either the Queries or Mutations models or both.
The Queries concern exposes read access by exposing query resolvers in the API.
The Mutations concern exposes write access by exposing create/update/delete resolvers in the API.
class Person < ApplicationRecord
include Graphoid::Queries
include Graphoid::Mutations
# columns are
# id: integer
# name: string
# money: float
# feet_size: string
has_many :accounts
has_one :horse
belongs_to :country
end
If you want to play with the autogenerated API at this point you can install GraphiQL
Run your server and visit http://localhost:3000/graphiql
There is a live demo where you can execute the queries of this document
The queries to fetch one or many records from the rails model will be autogerated.
You can make use of autogenerated filters too, see filters in the filters section
Model associations (has_many, belongs_to, etc) can be fetched and filtered too within the same query.
query {
person(id: 1) {
id
name
feetSize
accounts {
id
}
}
}
All of the attributes that were using snake case syntax (snake_case) in the ruby models are exposed in the queries/mutations as camel cased (camelCase).
query {
person(where: { name: "max" }) {
id
name
horse {
id
name
}
}
}
query {
people(where: { name_contains: "max" }) {
id
name
country {
id
name
}
}
}
Mutations to create, update and delete one or many records will be autogerated.
You can make use of autogenerated filters too in order to select what to update or delete.
mutation {
createPerson(data: { name: "bob" }) {
id
}
}
mutation {
createManyPeople(data: [{ name: "max" }, { name: "bob" }]) {
id
}
}
mutation {
createPerson(data: { name: "max", horse: { name: "unicorn" } }) {
id
}
}
mutation {
updatePerson(id: 1, data: { name: "bob" }) {
id
}
}
mutation {
updateManyPeople(where: { FILTER }, data: [{ name: "max" }]) {
id
}
}
mutation {
deletePerson(id: 1) {
id
}
}
mutation {
deleteManyPeople(where: { FILTER }) {
id
}
}
You can make use of the autogenerated filters to execute and get the result you want by properly applying them.
The available filters you can use are the ones listed below:
Get all people named bob
query {
people(where: { name: "bob" }) {
id
name
}
}
Get all people who are not named bob
query {
people(where: { name_not: "bob" }) {
id
name
}
}
Get all people that has a "b" on their name
query {
people(where: { name_contains: "b" }) {
id
name
}
}
Get all people that have a name with a letter between "a" and "g"
query {
people(where: { name_regex: "[a-g]/i" }) {
id
name
}
}
The Regex filter is only available if you are using mongoid.
Get all people who are named bob or maxi
query {
people(where: { name_in: ["max", "bob"] }) {
id
name
money
}
}
Get all people who are not named bob or maxi
query {
people(where: { name_nin: ["max", "bob"] }) {
id
name
}
}
Get all people with $30.30 or more money
query {
people(where: { money_gte: 30.3 }) {
id
name
money
}
}
Get all people named "max" and with more than $30
query {
people(where: {
AND: [
{ name: "max" },
{ money_gte: 30 }
]
}) {
id
name
money
}
}
query {
people(where: { name: "max", money_gte: 30 }) {
id
name
money
}
}
Get all people named "max" or with more than $30
query {
people(where: {
OR: [
{ name: "max" },
{ money_gte: 30 }
]
}) {
id
name
money
}
}
Graphoid will automatically inpect the relations that your model has and provide the corresponding API to query information on those relations too
Fetch all people with a white horse
query {
people(where: { horse: { color: "white" } }){
id
name
horse {
id
color
}
}
}
_some : fetch all people with a at least 1 google account
query {
people(where: { accounts_some: { name: "google" } }){
id
name
accounts {
id
name
}
}
}
_none : fetch all people without a google account
query {
people(where: { accounts_none: { name: "google" } }){
id
name
accounts {
id
name
}
}
}
_every: fetch all people that has only google accounts and no other accounts
query {
people(where: { accounts_every: { name: "google" } }){
id
name
accounts {
id
name
}
}
}
You can make use of the same filters described above to filter model associations
Fetch all people with all their google accounts. If a person had a facebook account, that account wont appear.
It does not affect the person model, only the accounts.
query {
people(){
id
name
accounts(where: { name: "google" }) {
id
name
}
}
}
Graphoid provides the "order" feature by any field that is present on the model
Fetch all people ordered descendently by name
query {
people(order: { name: DESC }){
id
name
}
}
The Graphield concern can be used to create new virtual attributes .
A virtual attribute always needs a method with the same name, in order to be resolved.
class Person
include Graphoid::Graphield
graphield :full_name, String
def full_name
"#{first_name} #{last_name}"
end
end
After defining how full_name is resolved you can use it on your queries.
query {
people(){
id
name
fullName
}
}
Graphield concern is also used to forbid access to existing fields.
One use would be not to expose the password field.
class Person
include Graphoid::Graphield
graphorbid :password # will not be exposed in the API
end
I am working very hard to include a dynamic field level permission system that is going to be highly configurable.
Meta queries are used to get data about the data.
query {
xMetaPeople(where: { name: "max" }) {
count
}
}
query {
xMetaPeople(where: { name: "max" }) {
id
name
sum(data: ["money"])
}
}
Aggregations is a feature that is still under development. Ideas for the syntax or implementation are very welcomed.