Error Handling with Connectors
Mapping responses for non-200 HTTP responses
Learn how Connectors handle errors by default and how you can customize error handling.
Default behavior
When an HTTP endpoint returns a non-200 status, GraphOS Router includes errors in the GraphQL errors array of the response. It uses the following default error structure:
{
"data": null,
"errors": [
{
"message": "Request failed",
"path": ["products"],
"extensions": {
"http": {
"status": 500
},
"connector": {
"coordinate": "ecomm:Query.products@connect[0]"
},
"code": "CONNECTOR_FETCH",
"service": "ecomm"
}
}
]
}Fields that return non-200 HTTP responses are set to null in the response's data attribute, following the GraphQL specification.
Error handling customization
You can customize errors in the response using the errors property on @source or @connect directives.
The errors property lets you customize the message and extensions fields in errors objects in the GraphQL response using information from the HTTP response and literal values.
{
"data": null,
"errors": [
{
"message": "Custom message",
"path": ["products"],
"extensions": {
"http": {
"customField": "Custom value"
},
/// ...
}
}
]
}The errors.message and errors.extensions fields take mapping expressions, which are applied on the response body, just like selection mapping.
You can access all of the mapping language's variables and methods in these fields.
Customizing errors.message
You can set a custom error message using the errors.message property on @connect and @source directives.
For example, this schema:
type Query {
users: [User]
@connect(
http: { GET: "http://my-api.com/users" }
selection: "id name"
errors: {
message: "error.message"
}
)
}results in a GraphQL response with a customized errors.message:
{
"data": null,
"errors": [
{
"message": "There was a critical failure!",
"path": ["users"],
/// ...
}
]
}The errors.message property expects a mapping expression that results in a string.
Valid error.message mapping expressions
The following are examples of valid mapping expressions for errors.message:
Using a static literal value:
GraphQL@connect( # --snip -- errors: { message: "$('This is a hard-coded literal message')" } )Using a response field (in particular,
error.message)`:GraphQL@connect( # --snip -- errors: { message: "error.message" } )Using a header value from the response with the
$response.headersvariable:GraphQL@connect( # --snip -- errors: { message: "$response.headers.errorheader->first" } )
Invalid error.message mapping expressions
The following are examples of invalid mapping expressions for errors.message:
Using a value that doesn't result in a string, for example, using the
$statusvariable, which returns a number:GraphQL❌ Invalid example@connect( # --snip -- errors: { message: "$status" } )Using an object format:
GraphQL❌ Invalid example@connect( # --snip -- errors: { message: "myProperty: error.message" } )
error.message precedence rules
If both @source and @connect set errors.message, the @connect's value takes precedence.
Customizing errors.extensions
You can set custom error extensions using the errors.extensions property on @connect and @source directives.
type Query {
users: [User]
@connect(
http: { GET: "http://my-api.com/users" }
selection: "id name"
errors: {
extensions: """
code: error.code
status: $status
"""
}
)
}This customization sets additional properties in the GraphQL errors.extensions object:
{
"data": null,
"errors": [
{
"message": "Request failed",
"path": ["users"],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"status": 500,
"http": {
"status": 500
},
"connector": {
"coordinate": "connector-graph:Query.users@connect[0]"
}
}
}
]
}The errors.extensions property expects a mapping expression that results in an object.
Valid errors.extensions mapping expressions
The following are examples of valid mapping expressions for errors.extensions:
Using properties from the response:
GraphQL@connect( # --snip -- errors: { extensions: """ code: error.code """ } )Using the
$statusvariable:GraphQL@connect( # --snip -- errors: { extensions: """ status: $status """ } )Using literal values in a nested structure:
GraphQL@connect( # --snip -- errors: { extensions: """ http: { myField: $("literal Value") } """ } )Combining multiple properties from different sources:
GraphQL@connect( # --snip -- errors: { extensions: """ code: error.code statusCode: $status errorDetails: { message: error.message timestamp: $response.headers."x-error-timestamp"->first source: $("backend-service") } """ } )
Invalid errors.extensions mapping expressions
The following example is invalid because it uses a value that doesn't result in an object:
@connect(
# --snip --
errors: {
extensions: "$status"
}
)errors.extensions precedence rules
If both @source and the @connect set errors.extensions properties, the response contains both. The extensions object also retains its default properties. When properties are found in more than one of the three:
Properties set in
@sourceoverwrite default propertiesProperties set in
@connectoverwrite@sourceproperties
Additional resources
Refer the mapping language documentation for more information on writing mapping expressions.
See the common errors section on the troubleshooting page for information on composition errors.