Skip to content

Instantly share code, notes, and snippets.

@karloku
Last active March 30, 2018 07:28
Show Gist options
  • Save karloku/edd6a158e275fdefa334 to your computer and use it in GitHub Desktop.
Save karloku/edd6a158e275fdefa334 to your computer and use it in GitHub Desktop.
Rails Template using GraphQL

This template is supposed to be applied to rails 5.

run with:

rails new <application_name> --template=https://gist.githubusercontent.com/karloku/edd6a158e275fdefa334/raw/b56175bee5b45d32310aeb620e23be44e3c2a56d/graphql_template.rb -T

using gems:

  • graphql
  • graphql-mutable_type
  • rolify
  • pundit
  • config
  • redcarpet
  • rouge
  • auto-space
  • nokogiri
  • redis-objects
  • kaminari
  • bcrypt
  • rack-cors
  • pry-rails
  • rspec-rails
  • factory_girl_rails
  • rubocop
  • paranoia(only when using ActiveRecord)
# GraphQL set for Tapas
gem 'graphql'
gem 'graphql-mutable_type'
# Authorization Set
gem 'rolify'
gem 'pundit'
# Config
gem 'config'
# Text Process
gem 'redcarpet', '~> 3.3.4'
gem 'rouge', '~> 1.8.0'
gem 'auto-space'
gem 'nokogiri'
# RedisObject
gem 'redis-objects'
# Pagination
gem 'kaminari'
# Use ActiveModel has_secure_password
gem 'bcrypt', '~> 3.1.7'
# Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible
gem 'rack-cors'
gem 'paranoia', github: 'radar/paranoia', branch: 'core' if yes?('Using ActiveRecord?')
# use rspec
gem_group :development, :test do
# pry
gem 'pry-rails'
# specs
gem 'rspec-rails', '~> 3.0'
gem 'factory_girl_rails', '~> 4.0'
# code style
gem 'rubocop', require: false
end
# Bundle
run('bundle install')
# initialize config
generate(:'config:install')
# initialize pundit
generate(:'pundit:install')
# initialize rspec
generate(:'rspec:install')
# initialize factory_girls
file 'spec/support/factory_girl.rb', <<-CODE
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
end
CODE
# load .rubocop.yml
run('curl -O https://gist.githubusercontent.com/karloku/7776105e8ccc38405ecc/raw/23e5b5d1174292d3e31d951169a49f9675de4e5f/.rubocop.yml')
# config graphql
application "config.autoload_paths += Dir[Rails.root.join('app', 'graph', '*')]"
run('mkdir app/graph')
run('mkdir app/graph/errors')
run('mkdir app/graph/helpers')
run('mkdir app/graph/scalar_types')
run('mkdir app/graph/types')
run('mkdir app/graph/queries')
run('mkdir app/graph/mutations')
run('mkdir app/graph/mutation_types')
## add GraphQL acronym inflection
initializer 'inflections.rb', <<-CODE
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.acronym 'GraphQL'
end
CODE
## initialize graphql errors
file 'app/graph/errors/custom_graphql_errors.rb', <<-CODE
module CustomGraphQLErrors
class Error < StandardError; end
# add your own errrors here
# class YourOwnError < Error; end
end
CODE
## initialize graphql helpers set
file 'app/graph/helpers/graphql_authorizer.rb', <<-CODE
# Use Pundit in GraphQL
module GraphQLArgumentProcessor
# Module Methods
module ModuleMethods
def camel_keys_to_underscore(arguments)
arguments.to_h
.stringify_keys
.transform_keys(&:underscore)
.symbolize_keys
end
end
extend ModuleMethods
end
CODE
file 'app/graph/helpers/graphql_argument_processor.rb', <<-CODE
# Use Pundit in GraphQL
module GraphQLArgumentProcessor
# Module Methods
module ModuleMethods
def camel_keys_to_underscore(arguments)
arguments.to_h
.stringify_keys
.transform_keys(&:underscore)
.symbolize_keys
end
end
extend ModuleMethods
end
CODE
file 'app/graph/helpers/graphql_authenticator.rb', <<-CODE
# Authenticate user in GraphQL
GraphQLAuthenticator = Struct.new(:object, :arguments, :context) do
def authenticate(&block)
authenticate_user!
execute(&block)
end
def execute(&block)
instance_exec(object, arguments, context, &block) if block_given?
end
def authenticate_user!
fail TapasGraphQLErrors::AuthenticationError if current_user.blank?
end
def current_user
@current_user ||= context.instance_variable_get(:'@values').present? && context[:current_user]
end
# Module Methods
module ModuleMethods
def authenticate(object, arguments, context, &block)
authenticator = new(object, arguments, context)
authenticator.authenticate(&block)
end
def execute(object, arguments, context, &block)
authenticator = new(object, arguments, context)
authenticator.execute(&block)
end
end
extend ModuleMethods
end
CODE
file 'app/graph/helpers/graphql_type_finder.rb', <<-CODE
module GraphQLTypeFinder
# Module Methods
module ModuleMethods
def find_by_name(name)
types.detect { |type| name == type.name }
end
def types
ObjectSpace.each_object(GraphQL::BaseType)
end
end
extend ModuleMethods
end
CODE
## initialize graphql extend scalar types
file 'app/graph/scalar_types/date_type.rb', <<-CODE
DateType = GraphQL::ScalarType.define do
name 'Date'
description 'ISO-8601 Format (YYYY-MM-DD\'T\'hh:mm:ss.sssZZZZZ)'
coerce_input -> (value) { Time.zone.parse value }
coerce_result -> (value) { value.as_json }
end
CODE
## initialize query root
file 'app/graph/query_type.rb', <<-CODE
# frozen_string_literal: true
QueryType = GraphQL::ObjectType.define do
name 'Query'
description 'Query Root'
# Add your queries here
# field :user, field: FetchField.create(User)
# Put your query fields under: queries/
# Put your data types under: types/
end
CODE
## initialize mutation root
file 'app/graph/mutation_type.rb', <<-CODE
MutationType = GraphQL::ObjectType.define do
name 'Mutation'
description 'Mutation Root'
# Add your mutations here
# field :createUser, field: FetchField.create(User)
# Put your mutations under: mutations/
# Define your mutation specific types under: mutation_types/
end
CODE
## initialize application schema
file 'app/graph/application_schema.rb', <<-CODE
ApplicationSchema = GraphQL::Schema.new(
query: QueryType,
mutation: MutationType
)
ApplicationSchema.instance_exec do
CustomGraphQLErrors::Error.descendants.each do |error_klass|
rescue_from error_klass, &:message
end
rescue_from Pundit::NotAuthorizedError do
::I18n.t('pundit.errors.message.not_authorized')
end
end
CODE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment