-
-
Notifications
You must be signed in to change notification settings - Fork 249
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow errors to send an error code in the response extension #246
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -95,4 +95,3 @@ object Client { | |
} | ||
|
||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -92,4 +92,32 @@ val i4: GraphQLInterpreter[MyEnv with Clock, CalibanError] = | |
_.getOrElse(GraphQLResponse(NullValue, List(ExecutionError("Timeout!")))) | ||
) | ||
) | ||
``` | ||
|
||
## Customizing error responses | ||
|
||
During various phases of executing a query, an error may occur. Caliban renders the different instances of `CalibanError` to a GraphQL spec compliant response. As a user, you will most likely encounter `ExecutionError` at some point because this will encapsulate the errors in the error channel of your effects. For Caliban to be able to render some basic message about the error that occured during query execution, it is important that your errror extends `Throwable`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. typo: errror There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed. |
||
|
||
For more meaningful error handling, GraphQL spec allows for an [`extension`](http://spec.graphql.org/June2018/#example-fce18) object in the error response. This object may include, for instance, `code` information to model enum-like error codes that can be handled by a front-end. In order to generate this information, one can use the `mapError` function on a `GraphQLInterpreter`. An example is provided below in which we map a custom domain error within an `ExecutionError` to a meaningful error code. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice doc! |
||
|
||
```scala | ||
sealed trait ExampleAppEncodableError extends Throwable { | ||
def errorCode: String | ||
} | ||
case object UnauthorizedError extends ExampleAppEncodableError { | ||
override def errorCode: String = "UNAUTHORIZED" | ||
} | ||
|
||
def withErrorCodeExtensions[R]( | ||
interpreter: GraphQLInterpreter[R, CalibanError] | ||
): GraphQLInterpreter[R, CalibanError] = interpreter.mapError { | ||
case err @ ExecutionError(_, _, _, Some(exampleError: ExampleAppEncodableError), _) => | ||
err.copy(extensions = Some(ObjectValue(List(("errorCode", StringValue(exampleError.errorCode)))))) | ||
case err: ExecutionError => | ||
err.copy(extensions = Some(ObjectValue(List(("errorCode", StringValue("EXECUTION_ERROR")))))) | ||
case err: ValidationError => | ||
err.copy(extensions = Some(ObjectValue(List(("errorCode", StringValue("VALIDATION_ERROR")))))) | ||
case err: ParsingError => | ||
err.copy(extensions = Some(ObjectValue(List(("errorCode", StringValue("PARSING_ERROR")))))) | ||
} | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(extensions: Option[ResponseValue])
would be better thanasInstanceOf
(here and below)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes a lot of sense but I can't seem to get the encoder for an
Option[ResponseValue]
in implicit scope such that.asJson
works. Thought that the implicitcirceEncoder
ofResponseValue
would be able to pick this one up? I got the.asInstanceOf[ResponseValue]
trick fromGraphQLResponse
actually.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(extensions: Option[ResponseValue]).asJson.dropNullValues
doesn't work? We were about to remove theasInstanceOf
in this PR by using that same trick: https://github.com/ghostdogpr/caliban/pull/234/files#diff-16ab822f0162e843af921d1e9d0c34dfR23There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aha, I was trying to put it in the match clause. Apparently didn't fully understand what you meant. Changed it now and it works!