lib/graphql/stitching/http_executable.rb in graphql-stitching-1.2.0 vs lib/graphql/stitching/http_executable.rb in graphql-stitching-1.2.1
- old
+ new
@@ -5,39 +5,48 @@
require "json"
module GraphQL
module Stitching
class HttpExecutable
- def initialize(url:, headers:{}, upload_types: nil)
+ # Builds a new executable for proxying subgraph requests via HTTP.
+ # @param url [String] the url of the remote location to proxy.
+ # @param headers [Hash] headers to include in upstream requests.
+ # @param upload_types [Array<String>, nil] a list of scalar names that represent file uploads. These types extract into multipart forms.
+ def initialize(url:, headers: {}, upload_types: nil)
@url = url
@headers = { "Content-Type" => "application/json" }.merge!(headers)
@upload_types = upload_types
end
def call(request, document, variables)
- multipart_form = if request.variable_definitions.any? && variables&.any?
- extract_multipart_form(request, document, variables)
- end
+ form_data = extract_multipart_form(request, document, variables)
- response = if multipart_form
- post_multipart(multipart_form)
+ response = if form_data
+ send_multipart_form(request, form_data)
else
- post(document, variables)
+ send(request, document, variables)
end
JSON.parse(response.body)
end
- def post(document, variables)
+ # Sends a POST request to the remote location.
+ # @param request [Request] the original supergraph request.
+ # @param document [String] the location-specific subgraph document to send.
+ # @param variables [Hash] a hash of variables specific to the subgraph document.
+ def send(_request, document, variables)
Net::HTTP.post(
URI(@url),
JSON.generate({ "query" => document, "variables" => variables }),
@headers,
)
end
- def post_multipart(form_data)
+ # Sends a POST request to the remote location with multipart form data.
+ # @param request [Request] the original supergraph request.
+ # @param form_data [Hash] a rendered multipart form with an "operations", "map", and file sections.
+ def send_multipart_form(_request, form_data)
uri = URI(@url)
req = Net::HTTP::Post.new(uri)
@headers.each_pair do |key, value|
req[key] = value
end
@@ -46,20 +55,22 @@
Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
http.request(req)
end
end
- # extract multipart upload forms
- # spec: https://github.com/jaydenseric/graphql-multipart-request-spec
+ # Extracts multipart upload forms per the spec:
+ # https://github.com/jaydenseric/graphql-multipart-request-spec
+ # @param request [Request] the original supergraph request.
+ # @param document [String] the location-specific subgraph document to send.
+ # @param variables [Hash] a hash of variables specific to the subgraph document.
def extract_multipart_form(request, document, variables)
- return unless @upload_types
+ return unless @upload_types && request.variable_definitions.any? && variables&.any?
- path = []
files_by_path = {}
# extract all upload scalar values mapped by their input path
- variables.each do |key, value|
+ variables.each_with_object([]) do |(key, value), path|
ast_node = request.variable_definitions[key]
path << key
extract_ast_node(ast_node, value, files_by_path, path, request) if ast_node
path.pop
end
@@ -68,17 +79,17 @@
map = {}
files = files_by_path.values.tap(&:uniq!)
variables_copy = variables.dup
- files_by_path.keys.each do |path|
+ files_by_path.each_key do |path|
orig = variables
copy = variables_copy
path.each_with_index do |key, i|
if i == path.length - 1
- map_key = files.index(copy[key]).to_s
- map[map_key] ||= []
- map[map_key] << "variables.#{path.join(".")}"
+ file_index = files.index(copy[key]).to_s
+ map[file_index] ||= []
+ map[file_index] << "variables.#{path.join(".")}"
copy[key] = nil
elsif orig[key].object_id == copy[key].object_id
copy[key] = copy[key].dup
end
orig = orig[key]