add graphql endpoint

This commit is contained in:
João Geonizeli
2021-08-03 20:25:26 -03:00
parent dccca02d1e
commit 5b88865de8
21 changed files with 197 additions and 6 deletions

View File

@@ -12,16 +12,17 @@ gem "rails", "~> 6.1.4"
gem "sass-rails", ">= 6"
gem "turbolinks", "~> 5"
gem "webpacker", "~> 5.0"
gem "bootsnap", ">= 1.4.4", require: false
gem "administrate"
gem "devise"
gem "devise-bootstrap-views", "~> 1.0"
gem "devise-i18n"
gem "administrate"
gem "graphql"
group :development, :test do
gem "graphql_playground-rails"
gem "pry-byebug", platforms: [:mri, :mingw, :x64_mingw]
gem "capybara"
gem "rspec-rails"
@@ -32,6 +33,7 @@ group :development, :test do
end
group :development do
gem "graphql_playground-rails"
gem "web-console", ">= 4.1.0"
gem "listen", "~> 3.3"

View File

@@ -106,6 +106,9 @@ GEM
ffi (1.15.3)
globalid (0.5.2)
activesupport (>= 5.0)
graphql (1.12.14)
graphql_playground-rails (2.1.0)
rails (>= 5.1.0)
i18n (1.8.10)
concurrent-ruby (~> 1.0)
jbuilder (2.11.2)
@@ -299,6 +302,8 @@ DEPENDENCIES
devise
devise-bootstrap-views (~> 1.0)
devise-i18n
graphql
graphql_playground-rails
jbuilder (~> 2.7)
listen (~> 3.3)
pg (~> 1.1)

View File

@@ -0,0 +1,51 @@
# frozen_string_literal: true
class GraphqlController < ApplicationController
# If accessing from outside this domain, nullify the session
# This allows for outside API access while preventing CSRF attacks,
# but you'll have to authenticate your user separately
# protect_from_forgery with: :null_session
def execute
variables = prepare_variables(params[:variables])
query = params[:query]
operation_name = params[:operationName]
context = {
# Query context goes here, for example:
current_user: current_admin_user,
}
result = XStakeSchema.execute(query, variables: variables, context: context, operation_name: operation_name)
render(json: result)
rescue StandardError => e
raise e unless Rails.env.development?
handle_error_in_development(e)
end
private
# Handle variables in form data, JSON body, or a blank value
def prepare_variables(variables_param)
case variables_param
when String
if variables_param.present?
JSON.parse(variables_param) || {}
else
{}
end
when Hash
variables_param
when ActionController::Parameters
variables_param.to_unsafe_hash # GraphQL-Ruby will validate name and type of incoming variables.
when nil
{}
else
raise ArgumentError, "Unexpected parameter: #{variables_param}"
end
end
def handle_error_in_development(e)
logger.error(e.message)
logger.error(e.backtrace.join("\n"))
render(json: { errors: [{ message: e.message, backtrace: e.backtrace }], data: {} }, status: :internal_server_error)
end
end

View File

View File

@@ -0,0 +1,9 @@
# frozen_string_literal: true
module Mutations
class BaseMutation < GraphQL::Schema::RelayClassicMutation
argument_class Types::BaseArgument
field_class Types::BaseField
input_object_class Types::BaseInputObject
object_class Types::BaseObject
end
end

0
app/graphql/types/.keep Normal file
View File

View File

@@ -0,0 +1,5 @@
# frozen_string_literal: true
module Types
class BaseArgument < GraphQL::Schema::Argument
end
end

View File

@@ -0,0 +1,7 @@
# frozen_string_literal: true
module Types
class BaseConnection < Types::BaseObject
# add `nodes` and `pageInfo` fields, as well as `edge_type(...)` and `node_nullable(...)` overrides
include GraphQL::Types::Relay::ConnectionBehaviors
end
end

View File

@@ -0,0 +1,7 @@
# frozen_string_literal: true
module Types
class BaseEdge < Types::BaseObject
# add `node` and `cursor` fields, as well as `node_type(...)` override
include GraphQL::Types::Relay::EdgeBehaviors
end
end

View File

@@ -0,0 +1,5 @@
# frozen_string_literal: true
module Types
class BaseEnum < GraphQL::Schema::Enum
end
end

View File

@@ -0,0 +1,6 @@
# frozen_string_literal: true
module Types
class BaseField < GraphQL::Schema::Field
argument_class Types::BaseArgument
end
end

View File

@@ -0,0 +1,6 @@
# frozen_string_literal: true
module Types
class BaseInputObject < GraphQL::Schema::InputObject
argument_class Types::BaseArgument
end
end

View File

@@ -0,0 +1,10 @@
# frozen_string_literal: true
module Types
module BaseInterface
include GraphQL::Schema::Interface
edge_type_class(Types::BaseEdge)
connection_type_class(Types::BaseConnection)
field_class Types::BaseField
end
end

View File

@@ -0,0 +1,8 @@
# frozen_string_literal: true
module Types
class BaseObject < GraphQL::Schema::Object
edge_type_class(Types::BaseEdge)
connection_type_class(Types::BaseConnection)
field_class Types::BaseField
end
end

View File

@@ -0,0 +1,5 @@
# frozen_string_literal: true
module Types
class BaseScalar < GraphQL::Schema::Scalar
end
end

View File

@@ -0,0 +1,7 @@
# frozen_string_literal: true
module Types
class BaseUnion < GraphQL::Schema::Union
edge_type_class(Types::BaseEdge)
connection_type_class(Types::BaseConnection)
end
end

View File

@@ -0,0 +1,11 @@
# frozen_string_literal: true
module Types
class MutationType < Types::BaseObject
# TODO: remove me
field :test_field, String, null: false,
description: "An example field added by the generator"
def test_field
"Hello World"
end
end
end

View File

@@ -0,0 +1,8 @@
# frozen_string_literal: true
module Types
module NodeType
include Types::BaseInterface
# Add the `id` field
include GraphQL::Types::Relay::NodeBehaviors
end
end

View File

@@ -0,0 +1,18 @@
# frozen_string_literal: true
module Types
class QueryType < Types::BaseObject
# Add `node(id: ID!) and `nodes(ids: [ID!]!)`
include GraphQL::Types::Relay::HasNodeField
include GraphQL::Types::Relay::HasNodesField
# Add root-level fields here.
# They will be entry points for queries on your schema.
# TODO: remove me
field :test_field, String, null: false,
description: "An example field added by the generator"
def test_field
context[:current_user].email
end
end
end

View File

@@ -0,0 +1,18 @@
# frozen_string_literal: true
class XStakeSchema < GraphQL::Schema
mutation(Types::MutationType)
query(Types::QueryType)
def self.resolve_type(abstract_type, obj, ctx)
raise(GraphQL::RequiredImplementationMissingError)
end
def self.id_from_object(object, type_definition, query_ctx)
GraphQL::Schema::UniqueWithinType.encode(type_definition.name, object.id)
end
def self.object_from_id(id, query_ctx)
type_name, item_id = GraphQL::Schema::UniqueWithinType.decode(id)
type_name.constantize.find(item_id)
end
end

View File

@@ -1,11 +1,14 @@
# frozen_string_literal: true
Rails.application.routes.draw do
mount GraphqlPlayground::Rails::Engine, at: "/playground", graphql_path: "/graphql" if Rails.env.development?
post "/graphql", to: "graphql#execute"
devise_for :admin_users
namespace :admin do
resources :admin_users
root to: "admin_users#index"
end
devise_for :admin_users
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end