pact-foundation / pact-jvm

JVM version of Pact. Enables consumer driven contract testing, providing a mock service and DSL for the consumer project, and interaction playback and verification for the service provider project.
https://docs.pact.io
Apache License 2.0
1.07k stars 473 forks source link

Add support for Graphql query in requests #1105

Open jarmy opened 4 years ago

jarmy commented 4 years ago

I’d like to write a consumer jvm test for a Graphql provider and I’m curious how I’d include the equivalent of {"query":"query Search{search(query: \"Drake\" types: [AR]) {items {id}}}"} in the request of my PactDslWithProvider object. It does not appear that the jvm implementation has an equivalent of the pact-js GraphQLInteraction as described here http://blog.pact.io/2018/07/24/contract-testing-a-graphql-api/

Relevant thread here https://pact-foundation.slack.com/archives/C9UN99H24/p1590699586329600

uglyog commented 4 years ago

Copied from slack channel:

Matt (pactflow.io / pact-js / pact-go) 13 minutes ago @Jason Army thanks for raising this

Matt (pactflow.io / pact-js / pact-go) 12 minutes ago Just so you know, the JS interface is a fairly lightweight shim over the existing interface. Because under the good, GraphQL actually sends a JSON payload with the gql query as a string, we construct a very crude regex

Matt (pactflow.io / pact-js / pact-go) 11 minutes ago so matchers and so on aren’t available - it really is just a string matcher

Matt (pactflow.io / pact-js / pact-go) 11 minutes ago My point is that you could basically do that yourself now in the JVM interface, I think (happy to give you pointers)

Jason Army 10 minutes ago I’ll happily take any pointers you can give

Matt (pactflow.io / pact-js / pact-go) 10 minutes ago Long term, we need to detect that it is a GraphQL interaction (there is no standard media type, sadly, because it’s actually JSON) and then convert into a GraphQL AST and do the matchers that way - so it’s a bit more involved

Matt (pactflow.io / pact-js / pact-go) 10 minutes ago -> this is the key code for JS: https://github.com/pact-foundation/pact-js/blob/master/src/dsl/graphql.ts#L43-L118

src/dsl/graphql.ts:43-118

* The actual GraphQL query as a string.
*
* NOTE: spaces are not important, Pact will auto-generate a space-insensitive matcher
*

Matt (pactflow.io / pact-js / pact-go) 7 minutes ago All it does is this: Takes the query, validates that it is indeed valid GraphQL syntax Generates the JSON HTTP payload (this is just a convenience wrapper really) Escapes the query string (edited)

Matt (pactflow.io / pact-js / pact-go) 2 minutes ago It will produce a contract that looks a bit like this:

{
  "consumer": {
    "name": "GraphQLConsumer"
  },
  "provider": {
    "name": "GraphQLProvider"
  },
  "interactions": [
    {
      "description": "a hello request",
      "request": {
        "method": "POST",
        "path": "/graphql",
        "headers": {
          "content-type": "application/json"
        },
        "body": {
          "operationName": "HelloQuery",
          "query": "\n          query HelloQuery {\n            hello\n          }\n        ",
          "variables": {
            "foo": "bar"
          }
        },
        "matchingRules": {
          "$.body.query": {
            "match": "regex",
            "regex": "\\s*query\\s*HelloQuery\\s*\\{\\s*hello\\s*\\}\\s*"
          }
        }
      },
      "response": {
        "status": 200,
        "headers": {
          "Content-Type": "application/json; charset=utf-8"
        },
        "body": {
          "data": {
            "hello": "Hello world!"
          }
        },
        "matchingRules": {
          "$.body.data.hello": {
            "match": "type"
          }
        }
      }
    }
  ],
  "metadata": {
    "pactSpecification": {
      "version": "2.0.0"
    }
  }
}

Matt (pactflow.io / pact-js / pact-go) 1 minute ago Ron - this should work similar to the XML stuff we recently did

Matt (pactflow.io / pact-js / pact-go) < 1 minute ago One key difference is that it’s both JSON and GraphQL

Matt (pactflow.io / pact-js / pact-go) < 1 minute ago It’s all JSON/HTTP, except for the query parameter (edited)