zammad/app/controllers/graphql_controller.rb

89 lines
2.4 KiB
Ruby
Raw Permalink Normal View History

# Copyright (C) 2012-2026 Zammad Foundation, https://zammad-foundation.org/
class GraphqlController < ApplicationController
# Handled in the GraphQL processing, not on controller level.
skip_before_action :verify_csrf_token
prepend_before_action lambda {
begin
authentication_check_only
rescue Exceptions::Forbidden
# Don't throw if the user is not authenticated. Just continue without a current_user.
end
}
def execute
if params[:_json]
return render json: multiplex
end
render json: single_query
rescue GraphqlValidations::Error => e
render json: { errors: [{ message: e.message }] }, status: :unprocessable_content
rescue => e
raise e if !Rails.env.development?
handle_error_in_development(e)
end
private
def multiplex
queries = params[:_json].map do |param|
{
query: param[:query],
operation_name: param[:operationName],
variables: prepare_variables(param[:variables]),
context: context
}
end
Gql::ZammadSchema.multiplex(queries)
end
def single_query
query = params[:query]
variables = prepare_variables(params[:variables])
operation_name = params[:operation_name]
Gql::ZammadSchema.execute(query, variables: variables, context: context, operation_name: operation_name)
end
def context
# context must be kept in sync with GraphqlChannel!
{
sid: session.id,
current_user: current_user,
current_user_id: current_user&.id,
# :controller is used by login/logout mutations and MUST NOT be used otherwise.
controller: self,
}
end
# 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