Skip to content

cclow/graphql-ruby

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

86 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

graphql

Build Status Gem Version Code Climate Test Coverage built with love

Create a GraphQL interface by implementing nodes and calls, then running queries.

Example Implementation

Usage

Create a GraphQL interface:

  • Implement nodes that wrap objects in your application
  • Implement calls that expose those objects (and may mutate the application state)
  • Execute queries on the system.

API docs: Ruby gem, master branch

Nodes

Nodes are delegators that wrap objects in your app. You must whitelist fields by declaring them in the class definition.

class FishNode < GraphQL::Node
  exposes "Fish"
  cursor(:id)
  field.number(:id)
  field.string(:name)
  field.string(:species)
  # specify an `AquariumNode`:
  field.aquarium(:aquarium)
end

You can also declare connections between objects:

class AquariumNode < GraphQL::Node
  exposes "Aquarium"
  cursor(:id)
  field.number(:id)
  field.number(:occupancy)
  field.connection(:fishes)
end

You can make custom connections:

class FishSchoolConnection < GraphQL::Connection
  type :fish_school # now it is a field type
  call :largest, -> (prev_value, number)  { fishes.sort_by(&:weight).first(number.to_i) }

  field.number(:count) # delegated to `target`
  field.boolean(:has_more)

  def has_more
    # the `largest()` call may have removed some items:
    target.count < original_target.count
  end
end

Then use them:

class AquariumNode < GraphQL::Node
  field.fish_school(:fishes)
end

And in queries:

aquarium(1) {
  name,
  occupancy,
  fishes.largest(3) {
      edges {
        node { name, species }
      },
      count,
      has_more
    }
  }
}

Calls

Calls selectively expose your application to the world. They always return values and they may perform mutations.

Calls declare returns, declare arguments, and implement #execute!.

This call just finds values:

class FindFishCall < GraphQL::RootCall
  returns :fish
  argument.number(:id)
  def execute!(id)
    Fish.find(id)
  end
end

This call performs a mutation:

class RelocateFishCall < GraphQL::RootCall
  returns :fish, :previous_aquarium, :new_aquarium
  argument.number(:fish_id)
  argument.number(:new_aquarium_id)

  def execute!(fish_id, new_aquarium_id)
    fish = Fish.find(fish_id)

    # context is defined by the query, see below
    if !context[:user].can_move?(fish)
      raise RelocateNotAllowedError
    end

    previous_aquarium = fish.aquarium
    new_aquarium = Aquarium.find(new_aquarium_id)
    fish.update_attributes(aquarium: new_aquarium)
    {
      fish: fish,
      previous_aquarium: previous_aquarium,
      new_aquarium: new_aquarium,
    }
  end
end

Queries

When your system is set up, you can perform queries from a string.

query_str = "find_fish(1) { name, species } "
query     = GraphQL::Query.new(query_str)
result    = query.as_result

result
# {
#   "1" => {
#     "name" => "Sharky",
#     "species" => "Goldfish",
#   }
# }

Each query may also define a context object which will be accessible at every point in execution.

query_str = "move_fish(1, 3) { fish { name }, new_aquarium { occupancy } }"
query_ctx = {user: current_user, request: request}
query     = GraphQL::Query.new(query_str, context: query_ctx)
result    = query.as_result

result
# {
#   "fish" => {
#     "name" => "Sharky"
#   },
#   "new_aquarium" => {
#     "occupancy" => 12
#   }
# }

You could do something like this inside a Rails controller.

To Do:

  • testing with JSON args
  • Make root calls plain ol' calls, on the root?
  • Make fields like calls with no args?
  • improve debugging experience
  • build nodes for Date, DateTime, Time, Hash
  • How do you express failure? HTTP response? errors key?
  • Handle blank objects in nested calls (how? wait for spec)
  • Implement calls as arguments
  • double-check how to handle pals.first(3) { count }
  • Implement call argument introspection (wait for spec)

About

Ruby implementation of Facebook's GraphQL

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Ruby 100.0%