-
Notifications
You must be signed in to change notification settings - Fork 99
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
misc: Split graphql definitions into two schemas
- Loading branch information
Showing
39 changed files
with
69,510 additions
and
102 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# frozen_string_literal: true | ||
|
||
module Graphql | ||
class ApiController < BaseController | ||
include AuthenticableUser | ||
include OrganizationHeader | ||
include Trackable | ||
|
||
def execute | ||
variables = prepare_variables(params[:variables]) | ||
query = params[:query] | ||
operation_name = params[:operationName] | ||
context = { | ||
current_user:, | ||
current_organization:, | ||
request:, | ||
permissions: | ||
current_user&.memberships&.find_by(organization: current_organization)&.permissions_hash || | ||
Permission::EMPTY_PERMISSIONS_HASH | ||
} | ||
|
||
OpenTelemetry::Trace.current_span.add_attributes({"query" => query, "operation_name" => operation_name}) | ||
result = LagoTracer.in_span("Schemas::ApiSchema.execute") do | ||
Schemas::ApiSchema.execute(query, variables:, context:, operation_name:) | ||
end | ||
|
||
render(json: result) | ||
rescue JWT::ExpiredSignature | ||
render_graphql_error(code: "expired_jwt_token", status: 401) | ||
rescue => e | ||
raise e unless Rails.env.development? | ||
|
||
handle_error_in_development(e) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# frozen_string_literal: true | ||
|
||
module Graphql | ||
class BaseController < ApplicationController | ||
before_action :set_context_source | ||
|
||
rescue_from JWT::ExpiredSignature do | ||
render_graphql_error(code: "expired_jwt_token", status: 401) | ||
end | ||
|
||
# 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 | ||
raise NotImplementedError | ||
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(error) | ||
logger.error(error.message) | ||
logger.error(error.backtrace.join("\n")) | ||
|
||
render(json: {errors: [{message: error.message, backtrace: error.backtrace}], data: {}}, status: 500) | ||
end | ||
|
||
def render_graphql_error(code:, status:, message: nil) | ||
render( | ||
json: { | ||
data: {}, | ||
errors: [ | ||
{ | ||
message: message || code, | ||
extensions: {status:, code:} | ||
} | ||
] | ||
} | ||
) | ||
end | ||
|
||
def set_context_source | ||
CurrentContext.source = 'graphql' | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# frozen_string_literal: true | ||
|
||
module Graphql | ||
class CustomerPortalController < BaseController | ||
include CustomerPortalUser | ||
|
||
def execute | ||
variables = prepare_variables(params[:variables]) | ||
query = params[:query] | ||
operation_name = params[:operationName] | ||
context = { | ||
customer_portal_user:, | ||
request: | ||
} | ||
|
||
OpenTelemetry::Trace.current_span.add_attributes({"query" => query, "operation_name" => operation_name}) | ||
result = LagoTracer.in_span("Schemas::CustomerPortalSchema.execute") do | ||
Schemas::CustomerPortalSchema.execute(query, variables:, context:, operation_name:) | ||
end | ||
|
||
render(json: result) | ||
rescue JWT::ExpiredSignature | ||
render_graphql_error(code: "expired_jwt_token", status: 401) | ||
rescue => e | ||
raise e unless Rails.env.development? | ||
|
||
handle_error_in_development(e) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
# frozen_string_literal: true | ||
|
||
module Schemas | ||
class ApiSchema < GraphQL::Schema | ||
mutation(Types::Api::MutationType) | ||
query(Types::Api::QueryType) | ||
|
||
# For batch-loading (see https://graphql-ruby.org/dataloader/overview.html) | ||
use GraphQL::Dataloader | ||
|
||
max_depth 15 | ||
max_complexity 350 | ||
|
||
# GraphQL-Ruby calls this when something goes wrong while running a query: | ||
|
||
# Union and Interface Resolution | ||
def self.resolve_type(_abstract_type, _obj, _ctx) | ||
# TODO: Implement this method | ||
# to return the correct GraphQL object type for `obj` | ||
raise(GraphQL::RequiredImplementationMissingError) | ||
end | ||
|
||
# Relay-style Object Identification: | ||
|
||
# Return a string UUID for `object` | ||
def self.id_from_object(object, type_definition, _query_ctx) | ||
# For example, use Rails' GlobalID library (https://github.com/rails/globalid): | ||
object_id = object.to_global_id.to_s | ||
# Remove this redundant prefix to make IDs shorter: | ||
object_id = object_id.sub("gid://#{GlobalID.app}/", '') | ||
encoded_id = Base64.urlsafe_encode64(object_id) | ||
# Remove the "=" padding | ||
encoded_id = encoded_id.sub(/=+/, '') | ||
# Add a type hint | ||
type_hint = type_definition.graphql_name.first | ||
"#{type_hint}_#{encoded_id}" | ||
end | ||
|
||
# Given a string UUID, find the object | ||
def self.object_from_id(encoded_id_with_hint, _query_ctx) | ||
# For example, use Rails' GlobalID library (https://github.com/rails/globalid): | ||
# Split off the type hint | ||
_type_hint, encoded_id = encoded_id_with_hint.split('_', 2) | ||
# Decode the ID | ||
id = Base64.urlsafe_decode64(encoded_id) | ||
# Rebuild it for Rails then find the object: | ||
full_global_id = "gid://#{GlobalID.app}/#{id}" | ||
GlobalID::Locator.locate(full_global_id) | ||
end | ||
|
||
default_max_page_size 25 | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
# frozen_string_literal: true | ||
|
||
module Schemas | ||
class CustomerPortalSchema < GraphQL::Schema | ||
mutation(Types::CustomerPortal::MutationType) | ||
query(Types::CustomerPortal::QueryType) | ||
|
||
# For batch-loading (see https://graphql-ruby.org/dataloader/overview.html) | ||
use GraphQL::Dataloader | ||
|
||
max_depth 15 | ||
max_complexity 350 | ||
|
||
# GraphQL-Ruby calls this when something goes wrong while running a query: | ||
|
||
# Union and Interface Resolution | ||
def self.resolve_type(_abstract_type, _obj, _ctx) | ||
# TODO: Implement this method | ||
# to return the correct GraphQL object type for `obj` | ||
raise(GraphQL::RequiredImplementationMissingError) | ||
end | ||
|
||
# Relay-style Object Identification: | ||
|
||
# Return a string UUID for `object` | ||
def self.id_from_object(object, type_definition, _query_ctx) | ||
# For example, use Rails' GlobalID library (https://github.com/rails/globalid): | ||
object_id = object.to_global_id.to_s | ||
# Remove this redundant prefix to make IDs shorter: | ||
object_id = object_id.sub("gid://#{GlobalID.app}/", '') | ||
encoded_id = Base64.urlsafe_encode64(object_id) | ||
# Remove the "=" padding | ||
encoded_id = encoded_id.sub(/=+/, '') | ||
# Add a type hint | ||
type_hint = type_definition.graphql_name.first | ||
"#{type_hint}_#{encoded_id}" | ||
end | ||
|
||
# Given a string UUID, find the object | ||
def self.object_from_id(encoded_id_with_hint, _query_ctx) | ||
# For example, use Rails' GlobalID library (https://github.com/rails/globalid): | ||
# Split off the type hint | ||
_type_hint, encoded_id = encoded_id_with_hint.split('_', 2) | ||
# Decode the ID | ||
id = Base64.urlsafe_decode64(encoded_id) | ||
# Rebuild it for Rails then find the object: | ||
full_global_id = "gid://#{GlobalID.app}/#{id}" | ||
GlobalID::Locator.locate(full_global_id) | ||
end | ||
|
||
default_max_page_size 25 | ||
end | ||
end |
Oops, something went wrong.