Sangria中的错误处理

关于 Scala 用的 GraphQL 库 Sangria 的以下错误处理。

    • (a) resolve 処理で例外が発生した場合

 

    (b) GraphQL クエリに問題があった場合

首先

这次是在以下环境下运行的。

构建.sbt
ThisBuild / scalaVersion := "3.2.1"

libraryDependencies ++= Seq(
  "org.sangria-graphql" %% "sangria" % "3.4.1",
  "org.sangria-graphql" %% "sangria-circe" % "1.3.2"
)

我們使用sangria-circe來將GraphQL的結果以JSON字符串的形式輸出。

如果发生异常,解决该问题。(If an exception occurs, resolve the issue.)

如果在处理过程中发生任何异常情况,默认的错误信息将是“Internal server error”。

比如,如果执行以下的处理

处理1
import sangria.schema.*
import sangria.execution.*
import sangria.macros.graphql
import sangria.marshalling.circe.*
import scala.concurrent.ExecutionContext

...

val QueryType = ObjectType("Query", fields[Unit, Unit](
  Field(
    "sample", 
    StringType, 
    arguments = Argument("input", StringType) :: Nil,
    resolve = c =>
      val input = c.args.arg[String]("input")

      if input.isBlank then
        throw Exception("input is blank")
      else
        s"ok-${input}"
  )
))

val schema = Schema(QueryType)

val q = graphql"""{ sample(input: "") }"""

given ExecutionContext = ExecutionContext.global

val r1 = Executor.execute(schema, q)
// r1 は Future(<not completed>)
r1.foreach(r => println(s"r1 result = ${r}"))

请注意,执行结果如下所示。请特别留意将其视为成功的未来情况。

执行结果1
r1 result = {
  "data" : null,
  "errors" : [
    {
      "message" : "Internal server error",
      "path" : [
        "sample"
      ],
      "locations" : [
        {
          "line" : 1,
          "column" : 3
        }
      ]
    }
  ]
}

可以使用ExceptionHandler来处理这种异常,并且可以使用HandledException来构建GraphQL格式的错误内容。

处理2 – ExceptionHandler的应用示例
// ExceptionHandler の実装
val exceptionHandler = ExceptionHandler {
  case (_, e) => {
    println(s"*** Error Handling: ${e}")
    // エラーメッセージを変更
    HandledException(e.getMessage)
  }
}

val r2 = Executor.execute(schema, q, exceptionHandler = exceptionHandler)
r2.foreach(r => println(s"r2 result = ${r}"))

异常处理程序的结果如下所示。

执行结果2
*** Error Handling: java.lang.Exception: input is blank
r2 result = {
  "data" : null,
  "errors" : [
    {
      "message" : "input is blank",
      "path" : [
        "sample"
      ],
      "locations" : [
        {
          "line" : 1,
          "column" : 3
        }
      ]
    }
  ]
}

如果在GraphQL查询中出现问题的话

接着,如果GraphQL查询本身存在问题,则异常处理程序无法处理,将以Future(Failure(sangria.execution.ValidationError: Query does not pass validation. Violations: ・・・ 的形式,Future本身被视为失败处理。

如果GraphQL查询存在问题
// 問題のあるクエリ(input 引数が未指定)
val q2 = graphql"{ sample }"

val r3 = Executor.execute(schema, q2, exceptionHandler = exceptionHandler)
// r3 が Future(Failure(sangria.execution.ValidationError)) となり foreach の処理は実行されない
r3.foreach(r => println(s"r3 result1 = ${r}"))

因此,似乎只能在Future的recover中处理错误。

似乎除了ValidationError之外,还有几种错误可用。然而,无论是哪种错误,基本上都实现了ErrorWithResolver trait,并且通过使用resolveError方法,可以获得GraphQL格式的错误结果{ …, “errors”: […] }。

处理3 – 查询错误处理示例
...

r3.recover {
  case e: ErrorWithResolver => e.resolveError
}.foreach(r => println(s"r3 result2 = ${r}"))
执行结果3
r3 result2 = {
  "data" : null,
  "errors" : [
    {
      "message" : "Field 'sample' argument 'input' of type 'String!' is required but not provided. (line 1, column 3):\n{ sample }\n  ^",
      "locations" : [
        {
          "line" : 1,
          "column" : 3
        }
      ]
    }
  ]
}

此外,还可以通过设置queryValidator来跳过对查询的验证,但是似乎无法在ExceptionHandler中处理,基本上最好不要使用。

不处理第四步- 跳过查询的验证
val r4 = Executor.execute(schema, q2, queryValidator = QueryValidator.empty)
// r4 は Future(<not completed>)
r4.foreach(r => println(s"r4 result = ${r}"))
运行结果为4。
r4 result = {
  "data" : null,
  "errors" : [
    {
      "message" : "Null value was provided for the NotNull Type 'String!' at path 'input'. (line 1, column 3):\n{ sample }\n  ^",
      "path" : [
        "sample"
      ],
      "locations" : [
        {
          "line" : 1,
          "column" : 3
        }
      ]
    }
  ]
}

这次的示例代码可以在 https://github.com/fits/try_samples/tree/master/blog/20230107/sangria_error_handling 上找到。

广告
将在 10 秒后关闭
bannerAds