是否可以在 Caliban 中为客户端使用 GraphQLRequest?

Is it possible to use GraphQLRequest for a client in Caliban?

我想测试我的 Caliban Http4s Web 服务。

Http4sAdapter 中,它使用 GraphQLRequest 为请求主体建模。

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

所以我想在客户端我也可以使用它。

一个简单的请求有效:

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

但是如果我使用变量它不会:

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

它只是挂起 - 甚至没有异常。

我试过 0.4.20.5.0

我添加了一个 Gist 来显示客户端代码。它使用 CirceSttpClient Gist

主要问题可以在你的要点中看出:编码到 JSON 中的变量不是服务器所期望的。

您目前拥有:

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

你应该只有:

"origin": "EARTH"

该值在卡利班中是 InputValue,而卡利班为 Circe 提供了一个 Encoder。但是,您似乎正在使用 Circe 通用自动推导,它没有获取 Caliban 的 Encoder 而是试图自己推导 InputValue,给出了不正确的结果。

我建议在 circe-generic 中使用半自动推导,甚至使用 circe-derivation 来正确获取 Caliban 的 Encoder。 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)

给出预期的 JSON:

{
  "query" : "query($origin: String){\n  characters(origin: $origin) {\n    name\n    nicknames\n    origin\n  }\n}",
  "operationName" : null,
  "variables" : {
    "origin" : "EARTH"
  }
}