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 上找到。