Class: Tina4::GraphQL

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

Overview

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(schema = nil) ⇒ GraphQL

Returns a new instance of GraphQL.



848
849
850
851
# File 'lib/tina4/graphql.rb', line 848

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

Instance Method Details

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

Execute a query string directly



854
855
856
857
858
859
860
861
862
# File 'lib/tina4/graphql.rb', line 854

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)



901
902
903
904
905
906
907
908
909
910
# File 'lib/tina4/graphql.rb', line 901

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.



894
895
896
897
898
# File 'lib/tina4/graphql.rb', line 894

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 = "/graphql") ⇒ 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


919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
# File 'lib/tina4/graphql.rb', line 919

def register_route(path = "/graphql")
  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.



865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
# File 'lib/tina4/graphql.rb', line 865

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