Class: Tina4::GraphQL

Inherits:
Object
  • Object
show all
Defined in:
lib/tina4/graphql.rb

Overview

─── Main GraphQL class ──────────────────────────────────────────────

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(schema = nil) ⇒ GraphQL

Returns a new instance of GraphQL.



856
857
858
859
# File 'lib/tina4/graphql.rb', line 856

def initialize(schema = nil)
  @schema = schema || GraphQLSchema.new
  @executor = GraphQLExecutor.new(@schema)
end

Instance Attribute Details

#schemaObject (readonly)

Returns the value of attribute schema.



846
847
848
# File 'lib/tina4/graphql.rb', line 846

def schema
  @schema
end

Class Method Details

.auto_schema_enabled?Boolean

Class-level toggle for ORM auto-schema generation. Defaults to true, can be disabled via TINA4_GRAPHQL_AUTO_SCHEMA=false. Initializers and user app code can branch on this before calling ‘schema.from_orm(…)`.

Returns:

  • (Boolean)


851
852
853
854
# File 'lib/tina4/graphql.rb', line 851

def self.auto_schema_enabled?
  val = ENV.fetch("TINA4_GRAPHQL_AUTO_SCHEMA", "true").to_s.strip.downcase
  !%w[false 0 no off].include?(val)
end

Instance Method Details

#execute(query, variables: {}, context: {}, operation_name: nil) ⇒ Object

Execute a query string directly



862
863
864
865
866
867
868
869
870
# File 'lib/tina4/graphql.rb', line 862

def execute(query, variables: {}, context: {}, operation_name: nil)
  parser = GraphQLParser.new(query)
  document = parser.parse
  @executor.execute(document, variables: variables, context: context, operation_name: operation_name)
rescue GraphQLError => e
  { "data" => nil, "errors" => [{ "message" => e.message }] }
rescue => e
  { "data" => nil, "errors" => [{ "message" => "Internal error: #{e.message}" }] }
end

#handle_request(body, context: {}) ⇒ Object

Handle an HTTP request body (JSON string)



909
910
911
912
913
914
915
916
917
918
# File 'lib/tina4/graphql.rb', line 909

def handle_request(body, context: {})
  payload = JSON.parse(body)
  query = payload["query"] || ""
  variables = payload["variables"] || {}
  op_name = payload["operationName"]

  execute(query, variables: variables, context: context, operation_name: op_name)
rescue JSON::ParserError
  { "data" => nil, "errors" => [{ "message" => "Invalid JSON in request body" }] }
end

#introspectObject

Return schema metadata for debugging.



902
903
904
905
906
# File 'lib/tina4/graphql.rb', line 902

def introspect
  queries = @schema.queries.transform_values { |v| { type: v[:type], args: v[:args] || {} } }
  mutations = @schema.mutations.transform_values { |v| { type: v[:type], args: v[:args] || {} } }
  { types: @schema.types.keys, queries: queries, mutations: mutations }
end

#register_route(path = nil) ⇒ Object

── Route Registration ─────────────────────────────────────────────Register a POST /graphql route in the Tina4 router.

gql = Tina4::GraphQL.new(schema)
gql.register_route           # POST /graphql
gql.register_route("/api/graphql")  # custom path


927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
# File 'lib/tina4/graphql.rb', line 927

def register_route(path = nil)
  # TINA4_GRAPHQL_ENDPOINT — defaults to /graphql when caller doesn't override.
  path ||= ENV.fetch("TINA4_GRAPHQL_ENDPOINT", "/graphql")
  path = path.to_s
  path = "/#{path}" unless path.start_with?("/")

  graphql = self
  Tina4.post path, auth: false do |request, response|
    body = request.body
    result = graphql.handle_request(body, context: { request: request })
    response.json(result)
  end

  # Optional: GET for GraphiQL/introspection
  Tina4.get path, auth: false do |request, response|
    query = request.params["query"]
    if query
      variables = request.params["variables"]
      variables = JSON.parse(variables) if variables.is_a?(String) && !variables.empty?
      result = graphql.execute(query, variables: variables || {}, context: { request: request })
      response.json(result)
    else
      response.html(graphiql_html(path))
    end
  end
end

#schema_sdlObject

Return schema as GraphQL SDL string.



873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
# File 'lib/tina4/graphql.rb', line 873

def schema_sdl
  sdl = ""
  @schema.types.each do |name, type_obj|
    sdl += "type #{name} {\n"
    type_obj.fields.each { |f| sdl += "  #{f[:name]}: #{f[:type]}\n" }
    sdl += "}\n\n"
  end
  unless @schema.queries.empty?
    sdl += "type Query {\n"
    @schema.queries.each do |name, config|
      args = (config[:args] || {}).map { |k, v| "#{k}: #{v}" }.join(", ")
      arg_str = args.empty? ? "" : "(#{args})"
      sdl += "  #{name}#{arg_str}: #{config[:type]}\n"
    end
    sdl += "}\n\n"
  end
  unless @schema.mutations.empty?
    sdl += "type Mutation {\n"
    @schema.mutations.each do |name, config|
      args = (config[:args] || {}).map { |k, v| "#{k}: #{v}" }.join(", ")
      arg_str = args.empty? ? "" : "(#{args})"
      sdl += "  #{name}#{arg_str}: #{config[:type]}\n"
    end
    sdl += "}\n\n"
  end
  sdl
end