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]