From d0e5a51187214162a5350fdc5a8f1ba1c1c62ac1 Mon Sep 17 00:00:00 2001 From: Myron Marston Date: Sun, 1 Dec 2024 00:03:57 -0800 Subject: [PATCH] Validate `variables` to make sure they are a JSON object as expected. The GraphQL gem internally raises an exception when given variables that are a string: ``` Query variables should be a Hash, not a String. Try JSON.parse to prepare variables. ``` This avoids that exception and returns a friendly 400 error when the client passes `variables` that are not an object as expected. --- .../lib/elastic_graph/graphql/http_endpoint.rb | 4 ++++ .../spec/unit/elastic_graph/graphql/http_endpoint_spec.rb | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/elasticgraph-graphql/lib/elastic_graph/graphql/http_endpoint.rb b/elasticgraph-graphql/lib/elastic_graph/graphql/http_endpoint.rb index d423ece6..420829c3 100644 --- a/elasticgraph-graphql/lib/elastic_graph/graphql/http_endpoint.rb +++ b/elasticgraph-graphql/lib/elastic_graph/graphql/http_endpoint.rb @@ -130,6 +130,10 @@ def with_request_params(request) # Ignore an empty string operationName. params = params.merge("operationName" => nil) if params["operationName"] && params["operationName"].empty? + if (variables = params["variables"]) && !variables.is_a?(::Hash) + return HTTPResponse.error(400, "Variables must be a JSON object but were not.") + end + yield params end diff --git a/elasticgraph-graphql/spec/unit/elastic_graph/graphql/http_endpoint_spec.rb b/elasticgraph-graphql/spec/unit/elastic_graph/graphql/http_endpoint_spec.rb index 7736b63a..152862b7 100644 --- a/elasticgraph-graphql/spec/unit/elastic_graph/graphql/http_endpoint_spec.rb +++ b/elasticgraph-graphql/spec/unit/elastic_graph/graphql/http_endpoint_spec.rb @@ -189,6 +189,13 @@ def with_context(request) expect(datastore_queries.size).to eq(1) expect(datastore_queries.first.filters.to_a).to eq [filter] end + + it "returns a 400 response when the variables are not a JSON object" do + query = "query Multiply($operands: Operands!) { multiply(operands: $operands) }" + response = process_graphql_expecting(400, query: query, variables: "not a JSON object") + + expect(response).to eq error_with("Variables must be a JSON object but were not.") + end end def submitted_value_for(option_name, ...)