Error handling
ApolloResponse
ApolloResponse
contains three important fields:
exception
contains the fetch error if any.errors
contains the GraphQL errors if any.data
contains the returned (potentially partial) data if any.
Use ApolloResponse.data
to check if the server returned data:
1if (response.data != null) {
2 // Handle (potentially partial) data
3} else {
4 // Something wrong happened
5 if (response.exception != null) {
6 // Handle fetch errors
7 } else {
8 // Handle GraphQL errors in response.errors
9 }
10}
This is also true when calling toFlow()
(e.g. with subscriptions) and watch()
(with the normalized cache).
1apolloClient.subscription(subscription).toFlow().collect { response ->
2 if (response.data != null) {
3 // Handle (potentially partial) data
4 } else {
5 if (response.exception != null) {
6 // Handle fetch errors
7 } else {
8 // Handle GraphQL errors in response.errors
9 }
10 }
11}
If you prefer throwing, you can use dataOrThrow()
to get a non-null data:
1val data = apolloClient.query(ExampleQuery()).execute().dataOrThrow()
2// data is non-null
Different types of errors
Whenever you execute a GraphQL operation with Apollo Kotlin (or any other GraphQL client), two types of errors can occur:
Fetch 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 fetch error occurs, no data is returned and
response.exception
is non-null.GraphQL errors: a GraphQL response is received (HTTP 200), and it contains a non-empty
errors
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.
Fetch errors
Fetch errors happen when it's impossible to fetch a GraphQL response. They can have a wide variety of causes (non-exhaustive list):
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.
And more...
You can display an error based on the exception in response.exception
GraphQL errors
GraphQL errors happen when a GraphQL response is successfully fetched but contains GraphQL errors. In that case, the response may contain partial data.
For example, the following query uses an invalid id
to look up a Person
:
1query FilmAndPersonQuery {
2 film(id: "ZmlsbXM6MQ==") {
3 title
4 }
5 person(id: "badId") {
6 name
7 }
8}
The server will return the following response:
1{
2 "data": {
3 "film": {
4 "title": "A New Hope"
5 },
6 "person": null
7 },
8 "errors": [
9 {
10 "message": "Cannot find person with id 'badId'",
11 "path": ["person"]
12 }
13 ]
14}
person
is null:
1// there was an error fetching data
2println(response.data?.person) // null
3// read the error from response.errors
4println(response.errors?.first()?.message) // "Cannot find person with id 'badId'"
5// partial data is also returned
6println(response.data?.film?.title) // "A New Hope"
7// exception is null
8println(response.exception) // null
This allows to display as much data as possible without having to do a new network round trip.
Because GraphQL models both errors and semantic nulls as nullable fields, you must check errors
to determine whether the field is an error or a true null.
For an example, it is possible for a person to not have a starship:
1{
2 "data": {
3 "person": {
4 "starship": null
5 }
6 }
7}
In that case, starship
is a true null and not an error.
Truth table
exception | data | errors | meaning |
---|---|---|---|
null | null | null | Non-compliant server, if data is null, there should be at least one error |
null | null | present | A GraphQL request error happened or a Graph field error bubbled up. |
null | present | null | Complete data was received. |
null | present | present | Partial data was received alongside field error(s). |
present | null | null | A fetch error happened. |
present | null | present | 🙅♂️ impossible. |
present | present | null | 🙅♂️ impossible. |
present | present | present | 🙅♂️ impossible. |