Errors
GraphQL has fine control for error handling. When executing a GraphQL operation, errors can be of two kinds:
- Transport errors: a GraphQL response wasn't received because a transport error happened. This can be a SSL error, a socket error because your app is offline or a 500 or any other HTTP error. In this case you will not get any data.
- GraphQL errors: a GraphQL response containing errors is received. This means the server wasn't able to completely process the query. You may get partial data if the server was able to process part of it.
Transport errors
Transport errors throw an ApolloException
. To handle them, wrap your query in a try/catch
block:
try {
val response = apolloClient.query(query)
} catch(exception: ApolloException) {
// handle exception here
}
Transport errors typically happen in these cases (non-limitative):
- The app is offline or doesn't have access to the network
- A DNS error happened, impossible to lookup the host
- A SSL error happened, the server certificate isn't trusted or something else
- The connection was closed
- Any non-successful HTTP error code
- The server did not send a valid json
- The response json doesn't satisy the schema and cannot be parsed
- A request was specified as CacheOnly but the data wasn't cached
Examine the exception to get more detailed information about the actual error happening.
GraphQL errors
Because GraphQL errors might still contain data, they do not throw but will instead return a Response
with a Response.errors
field indicating were the errors happened.
For an example, the below query uses a wrong id to lookup a person:
query FilmAndPersonQuery {
film(id: "ZmlsbXM6MQ==") {
title
}
person(id: "badId") {
name
}
}
The server will send the following response:
{
"data": {
"film": {
"title": "A New Hope"
},
"person": null
},
"errors": [
{
"message": "No entry in local cache for https://swapi.dev/api/people/m�H/",
"locations": [
{
"line": 35,
"column": 3
}
],
"path": [
"person"
]
}
]
}
Note that while there are errors, the query successfully returned the title of the film: "A New Hope". In general, any error while executing an operation will bubble up to the next nullable field. Here person
is nullable. In the worst case, response.data
can be null if everything else is non-nullable.
Apollo Android gives you access to both the data and the errors in the Response
class:
val response = try {
apolloClient.query(query)
} catch(exception: ApolloException) {
// transport error, not much to do
throw exception
}
// It's possible to display the film title
val title = response.data?.film?.title
if (title != null) {
println(title)
}
// The person triggered an error
val person = response.data?.person?.name
if (person != null) {
// do something with response.errors
}
If you don't want to handle partial responses you can use dataOrThrow()
that will return a non-nullable data and throw if there are any errors:
val data = try {
apolloClient.query(query).dataOrThrow
} catch(exception: ApolloException) {
// All transport or GraphQL errors are handled here
throw exception
}
// No need for safe calls on data
val title = data.film?.title
Note that the safe call is still required on film
because this field has a nullable type in the GraphQL schema. There are ways to override this in the codegen. See @nonnull for more details.