Skip to content

Commit

Permalink
Move ApolloParseException to ApolloNetworkException
Browse files Browse the repository at this point in the history
  • Loading branch information
martinbonnin committed Apr 15, 2024
1 parent f59f0b4 commit 1751b4c
Show file tree
Hide file tree
Showing 8 changed files with 43 additions and 27 deletions.
4 changes: 4 additions & 0 deletions libraries/apollo-api/api/apollo-api.api
Original file line number Diff line number Diff line change
Expand Up @@ -1304,6 +1304,10 @@ public final class com/apollographql/apollo3/exception/NoDataException : com/apo
public fun <init> (Ljava/lang/Throwable;)V
}

public final class com/apollographql/apollo3/exception/NullOrMissingField : com/apollographql/apollo3/exception/ApolloException {
public fun <init> (Ljava/lang/String;)V
}

public final class com/apollographql/apollo3/exception/RouterError : com/apollographql/apollo3/exception/ApolloException {
public fun <init> (Ljava/util/List;)V
public final fun getErrors ()Ljava/util/List;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
package com.apollographql.apollo3.api

import com.apollographql.apollo3.api.json.JsonReader
import com.apollographql.apollo3.exception.DefaultApolloException
import com.apollographql.apollo3.exception.NullOrMissingField
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName

Expand All @@ -13,7 +13,7 @@ import kotlin.jvm.JvmName
*/
fun checkFieldNotMissing(value: Any?, name: String) {
if (value == null) {
throw DefaultApolloException("Field '$name' is missing or null")
throw NullOrMissingField("Field '$name' is missing or null")
}
}

Expand All @@ -35,5 +35,5 @@ fun assertOneOf(vararg args: Optional<*>) {
* Helper function for the Kotlin codegen
*/
fun missingField(jsonReader: JsonReader, name: String): Nothing {
throw DefaultApolloException("Field '$name' is missing or null at path ${jsonReader.getPath()}")
throw NullOrMissingField("Field '$name' is missing or null at path ${jsonReader.getPath()}")
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import com.apollographql.apollo3.api.json.JsonReader
import com.apollographql.apollo3.api.json.JsonWriter
import com.apollographql.apollo3.api.json.writeObject
import com.apollographql.apollo3.exception.ApolloException
import com.apollographql.apollo3.exception.ApolloParseException
import com.apollographql.apollo3.exception.ApolloNetworkException
import com.apollographql.apollo3.exception.JsonDataException
import com.apollographql.apollo3.exception.JsonEncodingException
import com.benasher44.uuid.Uuid
Expand Down Expand Up @@ -114,10 +114,9 @@ fun <D : Operation.Data> Operation<D>.parseResponse(
val apolloException = if (throwable is ApolloException) {
throwable
} else {
// This happens for null pointer exceptions on missing fields
ApolloParseException(
message = "Failed to parse GraphQL http network response",
cause = throwable
ApolloNetworkException(
message = "Error while reading JSON response",
platformCause = throwable
)
}
return ApolloResponse.Builder(requestUuid = requestUuid ?: uuid4(), operation = this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import okio.BufferedSource
sealed class ApolloException(message: String? = null, cause: Throwable? = null) : RuntimeException(message, cause)

/**
* A generic exception when no additional context exists
* A generic exception used when there is no additional context besides the message.
*/
class DefaultApolloException(message: String? = null, cause: Throwable? = null): ApolloException(message, cause)

Expand All @@ -25,7 +25,10 @@ class DefaultApolloException(message: String? = null, cause: Throwable? = null):
class NoDataException(cause: Throwable?): ApolloException("No data was found", cause)

/**
* A network error happened: socket closed, DNS issue, TLS problem, etc...
* An I/O error happened: socket closed, DNS issue, TLS problem, file not found, etc...
*
* This is called [ApolloNetworkException] for historical reasons, but it should have been `ApolloIOException` instead.
* [ApolloNetworkException] is thrown when an I/O error happens reading the operation.
*
* @param message a message indicating what the error was.
* @param platformCause the underlying cause. Might be null. When not null, it can be cast to:
Expand Down Expand Up @@ -58,7 +61,6 @@ class SubscriptionConnectionException(
val payload: Any?,
) : ApolloException(message = "Subscription connection error")


/**
* The router sent one or several errors.
*
Expand Down Expand Up @@ -108,15 +110,26 @@ class JsonEncodingException(message: String) : ApolloException(message)
*
* Exceptions of this type should be fixed by either changing the application code to accept the unexpected JSON, or by changing the JSON
* to conform to the application's expectations.
*
* This exception may also be triggered if a document's nesting exceeds 31 levels. This depth is sufficient for all practical applications,
* but shallow enough to avoid uglier failures like [StackOverflowError].
*/
class JsonDataException(message: String) : ApolloException(message)

/**
* The response could not be parsed either because of another issue than [JsonDataException] or [JsonEncodingException]
* A field was missing or null in the JSON response.
*
* Due to the way the parsers work, it is not possible to distinguish between both cases.
*/
class NullOrMissingField(message: String): ApolloException(message)

/**
* The response could not be parsed because of an I/O exception.
*
* JSON and GraphQL errors are throwing other errors, see [JsonEncodingException], [JsonDataException] and [NullOrMissingField]
*
* @see JsonEncodingException
* @see JsonDataException
* @see NullOrMissingField
*/
@Deprecated("ApolloParseException was only used for I/O exceptions and is now mapped to ApolloNetworkException.")
class ApolloParseException(message: String? = null, cause: Throwable? = null) : ApolloException(message = message, cause = cause)

class ApolloGraphQLException(val error: Error): ApolloException("GraphQL error: '${error.message}'") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public <D extends Operation.Data> void execute(@NotNull ApolloRequest<D> request
}

@Override public void onFailure(@NotNull ApolloNetworkException exception) {
callback.onResponse(getExceptionResponse(request, new ApolloParseException("Cannot parse response", exception)));
callback.onResponse(getExceptionResponse(request, exception));
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import com.apollographql.apollo3.api.parseResponse
import com.apollographql.apollo3.api.toApolloResponse
import com.apollographql.apollo3.exception.ApolloException
import com.apollographql.apollo3.exception.ApolloHttpException
import com.apollographql.apollo3.exception.ApolloParseException
import com.apollographql.apollo3.exception.ApolloNetworkException
import com.apollographql.apollo3.exception.RouterError
import com.apollographql.apollo3.internal.DeferredJsonMerger
import com.apollographql.apollo3.internal.isMultipart
Expand Down Expand Up @@ -104,10 +104,9 @@ private constructor(
val apolloException = if (throwable is ApolloException) {
throwable
} else {
// This happens for null pointer exceptions on missing fields
ApolloParseException(
message = "Failed to parse GraphQL http network response",
cause = throwable
ApolloNetworkException(
message = "Error while reading JSON response",
platformCause = throwable
)
}
return ApolloResponse.Builder(requestUuid = uuid4(), operation = operation)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package test

import com.apollographql.apollo3.exception.DefaultApolloException
import com.apollographql.apollo3.exception.NullOrMissingField
import data.builders.fragment.AnimalDetailsImpl
import data.builders.fragment.CatDetailsImpl
import data.builders.fragment.TrivialFragmentImpl
Expand Down Expand Up @@ -43,7 +43,7 @@ class FragmentTest {
// __typename is unknown so this fails
// XXX: we could be smarter about this (the parsers are
// data.builders.fragment.AnimalDetailsImpl_ResponseAdapter$OnAnimal.fromJson(AnimalDetailsImpl_ResponseAdapter.kt:85)
assertFailsWith(DefaultApolloException::class) {
assertFailsWith(NullOrMissingField::class) {
TrivialFragmentImpl.Data(Animal) {
__typename = "Brontaroc"
species = "alien"
Expand Down
9 changes: 5 additions & 4 deletions tests/http-cache/src/test/kotlin/HttpCacheTest.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@

import com.apollographql.apollo3.ApolloClient
import com.apollographql.apollo3.cache.http.HttpFetchPolicy
import com.apollographql.apollo3.cache.http.httpCache
import com.apollographql.apollo3.cache.http.httpExpireTimeout
import com.apollographql.apollo3.cache.http.httpFetchPolicy
import com.apollographql.apollo3.cache.http.isFromHttpCache
import com.apollographql.apollo3.exception.ApolloParseException
import com.apollographql.apollo3.exception.ApolloNetworkException
import com.apollographql.apollo3.exception.HttpCacheMissException
import com.apollographql.apollo3.mockserver.MockServer
import com.apollographql.apollo3.mockserver.awaitRequest
Expand Down Expand Up @@ -212,9 +213,9 @@ class HttpCacheTest {
@Test
fun incompleteJsonIsNotCached() = runTest(before = { before() }, after = { tearDown() }) {
mockServer.enqueueString("""{"data":""")
assertIs<ApolloParseException>(
apolloClient.query(GetRandomQuery()).execute().exception
)
apolloClient.query(GetRandomQuery()).execute().exception.apply {
assertIs<ApolloNetworkException>(this)
}
// Should not have been cached
assertIs<HttpCacheMissException>(
apolloClient.query(GetRandomQuery()).httpFetchPolicy(HttpFetchPolicy.CacheOnly).execute().exception
Expand Down

0 comments on commit 1751b4c

Please sign in to comment.