Error handling
Whenever you execute a GraphQL operation with Apollo Kotlin (or any other GraphQL client), two high-level types of errors can occur:
- Network errors: a GraphQL response wasn't received because an error occurred while communicating with your GraphQL server. This might be an SSL error, a socket error because your app is offline, or a 500 or any other HTTP error. When a network error occurs, no data is returned.
- GraphQL errors: a GraphQL response is received, and it contains a non-empty field. This means the server wasn't able to completely process the query. The response might include partial data if the server was able to process some of the query.
errors
Network errors
Network errors throw an ApolloException
. To handle them, wrap your query in a try/catch
block:
try {val response = apolloClient.query(query).execute()} catch(exception: ApolloException) {// handle exception here}
Causes
Possible causes of a network error include (but are not limited to):
- The app is offline or doesn't have access to the network.
- A DNS error occurred, making it impossible to look up the host.
- An SSL error occurred (e.g., the server certificate isn't trusted).
- The connection was closed.
- The server responded with a non-successful HTTP code.
- The server didn't respond with valid JSON.
- The response JSON doesn't satisfy the schema and cannot be parsed.
- A request was specified as CacheOnly but the data wasn't cached.
Examine the exception for more detailed information about the actual error.
GraphQL errors
Because GraphQL errors might still contain data, they do not throw. Instead, they return a Response
with a Response.errors
field indicating the errors that occurred.
For example, the following query uses an invalid id
to look up 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 person
is nullable. In the worst case, response.data
can be null if everything else is non-nullable.
Apollo Kotlin gives you access to both the data and the errors in the Response
class:
val response = try {apolloClient.query(query).execute()} catch(exception: ApolloException) {// Network error, not much to dothrow exception}// It's possible to display the film titleval title = response.data?.film?.titleif (title != null) {println(title)}// The person triggered an errorval person = response.data?.person?.nameif (person != null) {// do something with response.errors}
Ignoring partial data
If you don't want to handle partial responses, you can simplify your error handling logic. ApolloResponse.dataAssertNoErrors
returns a non-nullable data
and throws if there are any errors. This way, you can handle all errors in a single catch {}
block:
val data = try {apolloClient.query(query).execute().dataAssertNoErrors} catch(exception: ApolloException) {// All network or GraphQL errors are handled herethrow exception}// No need for safe calls on dataval 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 codegen. For more details, learn about @nonnull
directive