0

I wanted to test my Caliban Http4s Webservice.

In Http4sAdapter it uses GraphQLRequest to model a Request Body.

case class GraphQLRequest(
   query: String,
   operationName: Option[String],
   variables: Option[Map[String, InputValue]])
...
query    <- req.attemptAs[GraphQLRequest].value.absolve
...

So I thought on the client side I could use it as well.

A simple Request works:

 GraphQLRequest("""query{
                         |  characters(origin: EARTH) {
                         |    name
                         |    nicknames
                         |    origin
                         |  }
                         |}""".stripMargin, None, None)

But if I use variables it doesn't:

GraphQLRequest("""query($origin: String){
                 |  characters(origin: $origin) {
                 |    name
                 |    nicknames
                 |    origin
                 |  }
                 |}""".stripMargin, None, Some(Map("origin" -> StringValue("EARTH"))))

It just hangs - there is not even an exception.

I tried with 0.4.2 and 0.5.0.

I added a Gist to show the client code. It uses Circe and Sttp: Client Gist

pme
  • 14,156
  • 3
  • 52
  • 95

1 Answers1

1

The main problem can be seen in your gist: the variables encoded into JSON are not what is expected by the server.

You currently have:

"origin": {
  "StringValue": {
    "value": "EARTH"
  }
}

and you should only have:

"origin": "EARTH"

That value is an InputValue in Caliban, and Caliban provides an Encoder for Circe. However you seem to be using Circe generic auto-derivation which is not picking up Caliban's Encoder but instead tries to derive InputValue on its own, giving an incorrect result.

I recommend using semi-auto derivation in circe-generic or even using circe-derivation which will pick up Caliban's Encoder properly. Example with circe-generic:

val req = GraphQLRequest(
  """query($origin: String){
    |  characters(origin: $origin) {
    |    name
    |    nicknames
    |    origin
    |  }
    |}""".stripMargin,
  None,
  Some(Map("origin" -> StringValue("EARTH")))
)

import io.circe.syntax._
import io.circe.generic.semiauto._
implicit val enc = deriveEncoder[GraphQLRequest]

println(req.asJson)

gives the expected JSON:

{
  "query" : "query($origin: String){\n  characters(origin: $origin) {\n    name\n    nicknames\n    origin\n  }\n}",
  "operationName" : null,
  "variables" : {
    "origin" : "EARTH"
  }
}
ghostdogpr
  • 631
  • 5
  • 9
  • ok it works now, thanks, but I had to use `import io.circe.derivation.deriveEncoder` – pme Jan 30 '20 at 18:26