Giter Site home page Giter Site logo

zyixc / graphql-rails-resolver Goto Github PK

View Code? Open in Web Editor NEW

This project forked from coleturner/graphql-rails-resolver

0.0 1.0 0.0 22 KB

A utility to ease graphql-ruby integration into a Rails project.

Home Page: https://rubygems.org/gems/graphql-rails-resolver

License: MIT License

Ruby 100.00%

graphql-rails-resolver's Introduction

GraphQL::Rails::Resolver (graphql-rails-resolver)

A utility to ease graphql-ruby integration into a Rails project. This resolver offers a declarative approach to resolving Field arguments in a Rails environment.

How it works

GraphQL::Rails::Resolver serves as a base class for your GraphQL Ruby schema. When a resolver inherits from this base class, you can easily map arguments in a GraphQL Field to an attribute on an ActiveRecord model or a custom method.

Why?

tl;dr; To achieves three goals: maintainable query type, code re-use, and a declarative integration with Ruby on Rails.

Take for example the following Rails model:

class Post < ApplicationRecord
  belongs_to :author
  has_many :comments

  scope :is_public, -> { where(is_public: true) }
  scope :is_private, -> { where(is_public: false) }
  scope :featured, -> (value) { where(created_at: value) }

  def tags
     ["hello", "world"]
  end

end

The standard implementation for resolving a Post is as follows:

field :post, PostType do
  argument :is_public, types.Boolean, default_value: true
  resolve -> (obj, args, ctx) {
    post.is_public if args[:is_public]
    post.is_private unless args[:is_public]
  }
end

This implementation is cumbersome and when your application grows it will become unmanageable. In GraphQL Ruby: Clean Up your Query Type we see a better pattern emerge for building resolvers that can be re-used.

Using the pattern from this article, our Field becomes much simpler:

/app/graph/types/query_type.rb

field :post, PostType do
  argument :is_public, types.Boolean, default_value: true
  resolve Resolvers::Post.new
end

/app/graph/resolvers/post.rb

module Resolvers
  class Post
    def call(_, arguments, _)
      if arguments[:ids]
        ::Post.where(id: arguments[:ids])
      elsif arguments.key? :is_public
        ::Post.is_public if arguments[:is_public]
        ::Post.is_private unless arguments[:is_public]
      else
        ::Post.all
      end
    end
  end
end

This solution addresses code re-use, but these series of conditionals do not allow you to resolve more than one argument, and it may become difficult to maintain this imperative approach.

Hello "Active" Resolver

Out with imperative, in with declarative.

To begin, we install the gem by adding it to our Gemfile:

gem 'graphql-rails-resolver'

This will load a class by the name of GraphQL::Rails::Resolver

Take the Resolver from the previous example. Using GraphQL::Rails::Resolver, we inherit and use declarations for arguments and how they will be resolved. These declarations will be mapped to the attributes on the resolved model.

# Class name must match the Rails model name exactly.

class Post < GraphQL::Rails::Resolver
  # ID argument is resolved in base class

  # Resolve :title, :created_at, :updated_at to Post.where() arguments
  resolve :title
  resolve :createdAt, :where => :created_at
  resolve :updatedAt, :where => :updated_at

  # Resolve :featured argument with default test: if argument `featured` is present
  resolve :featured, :scope => :featured

  # Same resolution as the line above, but send the value to the scope function
  resolve :featured, :scope => :featured, :with_value => true

  # Resolve :featured scope to a dynamic scope name
  resolve :is_public, :scope => -> (value) { value == true ? :is_public : :is_private}

  # Resolve :is_public to a class method
  resolve :custom_arg, :custom_resolve_method

  def custom_resolve_method(value)
    ...
  end

  # Resolve :is_public to a method on the model object
  resolve :custom_arg, :model_obj_method

end

In the examples above, the three primary arguments to resolve are:

resolve :argument_name, ...

where to specify another attribute.

scope to specify a scope on the model:

  • scope accepts string/symbol "scope name" or a closure that returns a scope name or nil
  • Use with_value to send the argument value to the scope closure.

Alternatively you can specify a symbol representing a method name: (ie: resolve :arg_1, :custom_method). The resolver will use it's own method if it exists, or else it will call the method on the object itself.

Detecting the Model

The resolver will automatically resolve to a Rails model with the same name. This behavior can be overridden by defining a Post#model which returns the appropriate model.

def model
   ::AnotherModel
end

Find Model by ID

GraphQL::Rails::Resolver includes the ability to resolve an object by ID (or a list of ID types). Using the following method, by default the resolver will find a model by Schema.object_from_id(value).

def object_from_id(value=...)
  ...
end

Override Default Scope

The default behavior is to use Model.all to scope the resolution. This scope can be changed by providing a block or lambda to the class instance:

Resolvers::Post.new(Proc.new {
	::Post.where(:created_at => ...)
})

Needs Help

I wanted to release this utility for the hopes of sparking interest in Rails integration with graphql-ruby. If you wish to contribute to this project, any pull request is warmly welcomed.

Credits

graphql-rails-resolver's People

Contributors

coleturner avatar

Watchers

Zyixc avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.