Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not throw in Flows #4685

Merged
merged 45 commits into from
Feb 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
be4442d
Add ApolloResponse.exception
BoD Feb 8, 2023
9fb7c53
Use exception in TestNetworkTransport
BoD Feb 13, 2023
d5e55e9
Do not throw in HttpNetworkTransport
BoD Feb 8, 2023
ff3bad0
Do not throw in WebSocketNetworkTransport
BoD Feb 14, 2023
c74efe3
Do not throw in ApolloCacheInterceptor
BoD Feb 8, 2023
2ee068e
Do not throw in FetchPolicyInterceptors
BoD Feb 10, 2023
f63f5ea
Return CompositeException in ApolloCall.execute()
BoD Feb 10, 2023
b37fab0
Simplify watch
BoD Feb 10, 2023
f27c8a4
Remove executeCacheAndNetwork
BoD Feb 10, 2023
0998dc4
Update API dump
BoD Feb 10, 2023
d75fe0f
Fix integration tests
BoD Feb 13, 2023
a8bab9d
Add back (legacy) throwing FetchPolicy interceptors, and throwApolloE…
BoD Feb 14, 2023
d841f79
Update libraries/apollo-api/src/commonMain/kotlin/com/apollographql/a…
BoD Feb 14, 2023
187d624
Clarify the new exception contract of NetworkTransport
BoD Feb 14, 2023
39737c5
Catch exceptions at the source in HttpNetworkTransport
BoD Feb 14, 2023
20ff36d
Simplify TestNetworkTransport
BoD Feb 14, 2023
dd1f710
Add throwOnException to ExecuteOptions and use that in toFlow.
BoD Feb 15, 2023
b226f0d
Add foldFetchExceptions to MutableExecutionOptions and use that in fe…
BoD Feb 15, 2023
4ce2c75
Update api dump
BoD Feb 15, 2023
aab0b08
Fix HeadersTest
BoD Feb 15, 2023
96a6ed0
Port not throwing exceptions over to the incubating cache module
BoD Feb 15, 2023
1158691
Fix pagination unit test
BoD Feb 15, 2023
719b1ae
Don't throw in ApolloInterceptors
BoD Feb 15, 2023
d06a21a
Java Runtime: remove ApolloCallback.onFailure, exceptions are returne…
BoD Feb 16, 2023
74e3bf8
Update API dump
BoD Feb 16, 2023
7b15108
Actually this is a programmer error, so let's throw
BoD Feb 16, 2023
a777156
Update libraries/apollo-normalized-cache-incubating/src/commonMain/ko…
BoD Feb 17, 2023
544b842
Update libraries/apollo-normalized-cache-incubating/src/commonMain/ko…
BoD Feb 17, 2023
1400832
Update libraries/apollo-normalized-cache-incubating/src/commonMain/ko…
BoD Feb 17, 2023
3eedfa1
Update libraries/apollo-normalized-cache-incubating/src/commonMain/ko…
BoD Feb 17, 2023
271dcf1
keep apollo-normalized-cache and apollo-normalized-cache-incubating i…
martinbonnin Feb 17, 2023
5e8632d
Cross-reference exceptions and errors in KDoc
BoD Feb 17, 2023
6ceba62
Improve FetchPolicy KDoc
BoD Feb 17, 2023
b50ad0b
Centralize folding exceptions in FetchPolicyRouterInterceptor
BoD Feb 17, 2023
a190d88
Better doc in NetworkTransport
BoD Feb 17, 2023
929aef6
Do not throw in ApolloCall.execute()
BoD Feb 17, 2023
0854d67
Don't set cacheInfo multiple times
BoD Feb 20, 2023
63870da
Improve execute() readability and allow more than 2 exceptions in Apo…
BoD Feb 20, 2023
fbc2cf3
Improve ApolloResponse.errors KDoc
BoD Feb 20, 2023
d4f4390
Deprecate dataAssertNoErrors.
BoD Feb 20, 2023
34d8588
Remove foldFetchExceptions, instead use useV3ExceptionHandling.
BoD Feb 20, 2023
2fde153
Check for response.exception in maybeWriteToCache
BoD Feb 20, 2023
503380c
Revert deprecation of dataAssertNoErrors for now
BoD Feb 21, 2023
aa08587
Deprecate emitCacheMisses as warning, not error. Also, throw in unsup…
BoD Feb 21, 2023
9c9da5c
Fix watch signature
BoD Feb 21, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions libraries/apollo-annotations/api/apollo-annotations.api
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public final class com/apollographql/apollo3/annotations/ApolloDeprecatedSince$V
public static final field v3_5_1 Lcom/apollographql/apollo3/annotations/ApolloDeprecatedSince$Version;
public static final field v3_6_3 Lcom/apollographql/apollo3/annotations/ApolloDeprecatedSince$Version;
public static final field v3_7_2 Lcom/apollographql/apollo3/annotations/ApolloDeprecatedSince$Version;
public static final field v3_7_5 Lcom/apollographql/apollo3/annotations/ApolloDeprecatedSince$Version;
public static final field v4_0_0 Lcom/apollographql/apollo3/annotations/ApolloDeprecatedSince$Version;
public static fun valueOf (Ljava/lang/String;)Lcom/apollographql/apollo3/annotations/ApolloDeprecatedSince$Version;
public static fun values ()[Lcom/apollographql/apollo3/annotations/ApolloDeprecatedSince$Version;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ annotation class ApolloDeprecatedSince(val version: Version) {
v3_4_1,
v3_5_1,
v3_6_3,
v3_7_2
v3_7_2,
v3_7_5,
v4_0_0,
}
}
7 changes: 5 additions & 2 deletions libraries/apollo-api/api/apollo-api.api
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public final class com/apollographql/apollo3/api/ApolloOptionalAdapter : com/apo
}

public final class com/apollographql/apollo3/api/ApolloRequest : com/apollographql/apollo3/api/ExecutionOptions {
public synthetic fun <init> (Lcom/apollographql/apollo3/api/Operation;Ljava/util/UUID;Lcom/apollographql/apollo3/api/ExecutionContext;Lcom/apollographql/apollo3/api/http/HttpMethod;Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun <init> (Lcom/apollographql/apollo3/api/Operation;Ljava/util/UUID;Lcom/apollographql/apollo3/api/ExecutionContext;Lcom/apollographql/apollo3/api/http/HttpMethod;Ljava/util/List;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Ljava/lang/Boolean;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun getCanBeBatched ()Ljava/lang/Boolean;
public fun getEnableAutoPersistedQueries ()Ljava/lang/Boolean;
public fun getExecutionContext ()Lcom/apollographql/apollo3/api/ExecutionContext;
Expand Down Expand Up @@ -113,12 +113,13 @@ public final class com/apollographql/apollo3/api/ApolloRequest$Builder : com/apo
public final class com/apollographql/apollo3/api/ApolloResponse {
public final field data Lcom/apollographql/apollo3/api/Operation$Data;
public final field errors Ljava/util/List;
public final field exception Lcom/apollographql/apollo3/exception/ApolloException;
public final field executionContext Lcom/apollographql/apollo3/api/ExecutionContext;
public final field extensions Ljava/util/Map;
public final field isLast Z
public final field operation Lcom/apollographql/apollo3/api/Operation;
public final field requestUuid Ljava/util/UUID;
public synthetic fun <init> (Ljava/util/UUID;Lcom/apollographql/apollo3/api/Operation;Lcom/apollographql/apollo3/api/Operation$Data;Ljava/util/List;Ljava/util/Map;Lcom/apollographql/apollo3/api/ExecutionContext;ZLkotlin/jvm/internal/DefaultConstructorMarker;)V
public synthetic fun <init> (Ljava/util/UUID;Lcom/apollographql/apollo3/api/Operation;Lcom/apollographql/apollo3/api/Operation$Data;Ljava/util/List;Lcom/apollographql/apollo3/exception/ApolloException;Ljava/util/Map;Lcom/apollographql/apollo3/api/ExecutionContext;ZLkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun dataAssertNoErrors ()Lcom/apollographql/apollo3/api/Operation$Data;
public final fun hasErrors ()Z
public final fun newBuilder ()Lcom/apollographql/apollo3/api/ApolloResponse$Builder;
Expand All @@ -129,6 +130,7 @@ public final class com/apollographql/apollo3/api/ApolloResponse$Builder {
public final fun addExecutionContext (Lcom/apollographql/apollo3/api/ExecutionContext;)Lcom/apollographql/apollo3/api/ApolloResponse$Builder;
public final fun build ()Lcom/apollographql/apollo3/api/ApolloResponse;
public final fun errors (Ljava/util/List;)Lcom/apollographql/apollo3/api/ApolloResponse$Builder;
public final fun exception (Lcom/apollographql/apollo3/exception/ApolloException;)Lcom/apollographql/apollo3/api/ApolloResponse$Builder;
public final fun extensions (Ljava/util/Map;)Lcom/apollographql/apollo3/api/ApolloResponse$Builder;
public final fun isLast (Z)Lcom/apollographql/apollo3/api/ApolloResponse$Builder;
public final fun requestUuid (Ljava/util/UUID;)Lcom/apollographql/apollo3/api/ApolloResponse$Builder;
Expand Down Expand Up @@ -1148,6 +1150,7 @@ public final class com/apollographql/apollo3/api/test/TestResolverKt {

public final class com/apollographql/apollo3/exception/ApolloCompositeException : com/apollographql/apollo3/exception/ApolloException {
public fun <init> (Ljava/lang/Throwable;Ljava/lang/Throwable;)V
public fun <init> (Ljava/util/List;)V
}

public class com/apollographql/apollo3/exception/ApolloException : java/lang/RuntimeException {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.apollographql.apollo3.api

import com.apollographql.apollo3.annotations.ApolloExperimental
import com.apollographql.apollo3.annotations.ApolloInternal
import com.apollographql.apollo3.api.http.HttpHeader
import com.apollographql.apollo3.api.http.HttpMethod
import com.benasher44.uuid.Uuid
Expand All @@ -20,12 +21,16 @@ private constructor(
override val sendDocument: Boolean?,
override val enableAutoPersistedQueries: Boolean?,
override val canBeBatched: Boolean?,

@ApolloInternal
val useV3ExceptionHandling: Boolean?,
) : ExecutionOptions {

fun newBuilder(): Builder<D> = newBuilder(operation)

@ApolloExperimental
fun <E: Operation.Data> newBuilder(operation: Operation<E>): Builder<E> {
@Suppress("DEPRECATION")
return Builder(operation)
.requestUuid(requestUuid)
.executionContext(executionContext)
Expand All @@ -35,7 +40,7 @@ private constructor(
.sendDocument(sendDocument)
.enableAutoPersistedQueries(enableAutoPersistedQueries)
.canBeBatched(canBeBatched)

.useV3ExceptionHandling(useV3ExceptionHandling)
}

class Builder<D : Operation.Data>(
Expand Down Expand Up @@ -84,6 +89,13 @@ private constructor(
this.canBeBatched = canBeBatched
}

private var useV3ExceptionHandling: Boolean? = null

@ApolloInternal
fun useV3ExceptionHandling(useV3ExceptionHandling: Boolean?): Builder<D> = apply {
this.useV3ExceptionHandling = useV3ExceptionHandling
}

fun requestUuid(requestUuid: Uuid) = apply {
this.requestUuid = requestUuid
}
Expand All @@ -108,6 +120,7 @@ private constructor(
sendDocument = sendDocument,
enableAutoPersistedQueries = enableAutoPersistedQueries,
canBeBatched = canBeBatched,
useV3ExceptionHandling = useV3ExceptionHandling,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,28 @@ private constructor(
val data: D?,

/**
* GraphQL [operation] execution errors returned by the server to let client know that something has gone wrong.
* This can either be null or empty depending on what your server sends back
* [GraphQL errors](https://spec.graphql.org/October2021/#sec-Errors) returned by the server to let the client know that something
* has gone wrong.
*
* If no GraphQL error was raised, [errors] is null. Else it's a non-empty list of errors indicating where the error(s) happened.
*
* Note that because GraphQL allows partial data, it is possible to have both [data] non null and [errors] non null.
*
* See also [exception] for exceptions happening before a valid GraphQL response could be received.
*/
@JvmField
val errors: List<Error>?,

/**
* An [ApolloException] if a valid GraphQL response wasn't received or `null` if a valid GraphQL response was received.
* For example, `exception` is non null if there is a network failure or cache miss.
* If `exception` is non null, [data] and [errors] will be null.
martinbonnin marked this conversation as resolved.
Show resolved Hide resolved
*
* See also [errors] for GraphQL errors returned by the server.
*/
@JvmField
val exception: ApolloException?,

/**
* Extensions of GraphQL protocol, arbitrary map of key [String] / value [Any] sent by server along with the response.
*/
Expand Down Expand Up @@ -71,10 +87,10 @@ private constructor(
@get:JvmName("dataAssertNoErrors")
val dataAssertNoErrors: D
martinbonnin marked this conversation as resolved.
Show resolved Hide resolved
get() {
return if (hasErrors()) {
throw ApolloException("The response has errors: $errors")
} else {
data ?: throw ApolloException("The server did not return any data")
return when {
exception != null -> throw exception
hasErrors() -> throw ApolloException("The response has errors: $errors")
else -> data ?: throw ApolloException("The server did not return any data")
}
}

Expand All @@ -83,6 +99,7 @@ private constructor(
fun newBuilder(): Builder<D> {
return Builder(operation, requestUuid, data)
.errors(errors)
.exception(exception)
.extensions(extensions)
.addExecutionContext(executionContext)
.isLast(isLast)
Expand All @@ -95,6 +112,7 @@ private constructor(
) {
private var executionContext: ExecutionContext = ExecutionContext.Empty
private var errors: List<Error>? = null
private var exception: ApolloException? = null
private var extensions: Map<String, Any?>? = null
private var isLast = false

Expand All @@ -106,6 +124,10 @@ private constructor(
this.errors = errors
}

fun exception(exception: ApolloException?) = apply {
this.exception = exception
}

fun extensions(extensions: Map<String, Any?>?) = apply {
this.extensions = extensions
}
Expand All @@ -127,6 +149,7 @@ private constructor(
executionContext = executionContext,
extensions = extensions ?: emptyMap(),
errors = errors,
exception = exception,
isLast = isLast,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,27 @@ interface ExecutionOptions {
val httpHeaders: List<HttpHeader>?

/**
*
* Whether to send the Auto Persisted Queries extensions
* Whether to send the Auto Persisted Queries extensions.
* Used by [com.apollographql.apollo3.api.http.DefaultHttpRequestComposer]
*/
val sendApqExtensions: Boolean?

/**
*
* Whether to send the document
* Whether to send the document.
* Used by [com.apollographql.apollo3.api.http.DefaultHttpRequestComposer]
*/
val sendDocument: Boolean?

/**
*
* Whether to enable Auto Persisted Queries and try to send a hashed query first
* Whether to enable Auto Persisted Queries and try to send a hashed query first.
* Used by [com.apollographql.apollo3.interceptor.AutoPersistedQueryInterceptor]
*/
val enableAutoPersistedQueries: Boolean?

/**
* Whether the request can be batched.
* Used by [com.apollographql.apollo3.network.http.BatchingHttpInterceptor]
*/
val canBeBatched: Boolean?

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import com.apollographql.apollo3.api.json.JsonReader
import com.apollographql.apollo3.api.json.JsonWriter
import com.apollographql.apollo3.api.json.jsonReader
import com.apollographql.apollo3.api.json.writeObject
import com.apollographql.apollo3.exception.JsonDataException
import com.apollographql.apollo3.exception.JsonEncodingException
import okio.Buffer
import okio.IOException
import okio.use
import kotlin.jvm.JvmName
import kotlin.jvm.JvmOverloads
Expand Down Expand Up @@ -53,6 +56,10 @@ fun <D : Operation.Data> Operation<D>.composeJsonRequest(
* ```
*
* This method takes ownership of [jsonReader] and will always close it
*
* @throws IOException if reading [jsonReader] fails
* @throws JsonEncodingException if the data is not valid json
* @throws JsonDataException if the data is not of the expected type
*/
@JvmOverloads
fun <D : Operation.Data> Operation<D>.parseJsonResponse(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ class CacheMissException @ApolloInternal constructor(
@ApolloExperimental
val stale: Boolean = stale

constructor(key: String, fieldName: String?): this(key, fieldName, false)
constructor(key: String, fieldName: String?) : this(key, fieldName, false)

companion object {
internal fun message(key: String?, fieldName: String?, stale: Boolean): String {
Expand Down Expand Up @@ -158,12 +158,15 @@ class HttpCacheMissException(message: String, cause: Exception? = null) : Apollo
* }
* ```
*/
class ApolloCompositeException(first: Throwable?, second: Throwable?) : ApolloException(message = "multiple exceptions happened", second) {
init {
class ApolloCompositeException : ApolloException {
constructor(first: Throwable?, second: Throwable?) : super(message = "Multiple exceptions happened", second) {
if (first != null) addSuppressed(first)
if (second != null) addSuppressed(second)
}

constructor(exceptions: List<Throwable>) : super(message = "Multiple exceptions happened", exceptions.lastOrNull()) {
exceptions.forEach { addSuppressed(it) }
}
}

class AutoPersistedQueriesNotSupported : ApolloException(message = "The server does not support auto persisted queries")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import com.apollographql.apollo3.network.http.HttpInterceptor
import com.apollographql.apollo3.network.http.HttpInterceptorChain
import com.apollographql.apollo3.network.http.HttpNetworkTransport
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onEach
Expand Down Expand Up @@ -120,15 +119,10 @@ fun ApolloClient.Builder.httpCache(
)
.run {
if (request.operation is Query<*> || request.operation is Mutation<*>) {
catch { throwable ->
onEach { response ->
// Revert caching of responses with errors
val cacheKey = synchronized(apolloRequestToCacheKey) { apolloRequestToCacheKey[request.requestUuid.toString()] }
cacheKey?.let { cachingHttpInterceptor.cache.remove(it) }
throw throwable
}.onEach { response ->
// Revert caching of responses with errors
val cacheKey = synchronized(apolloRequestToCacheKey) { apolloRequestToCacheKey[request.requestUuid.toString()] }
if (response.hasErrors()) {
if (response.hasErrors() || response.exception != null) {
martinbonnin marked this conversation as resolved.
Show resolved Hide resolved
cacheKey?.let { cachingHttpInterceptor.cache.remove(it) }
}
}.onCompletion {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,20 @@
package com.apollographql.apollo3.cache.normalized

import com.apollographql.apollo3.interceptor.ApolloInterceptor
import com.apollographql.apollo3.interceptor.ApolloInterceptorChain
import com.apollographql.apollo3.api.ApolloRequest
import com.apollographql.apollo3.api.ApolloResponse
import com.apollographql.apollo3.api.Operation
import com.apollographql.apollo3.exception.CacheMissException
import com.apollographql.apollo3.interceptor.ApolloInterceptor
import com.apollographql.apollo3.interceptor.ApolloInterceptorChain
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.onEach

class CacheMissLoggingInterceptor(private val log: (String) -> Unit) : ApolloInterceptor {
override fun <D : Operation.Data> intercept(request: ApolloRequest<D>, chain: ApolloInterceptorChain): Flow<ApolloResponse<D>> {
return chain.proceed(request).onEach {
it.cacheInfo?.cacheMissException?.message?.let {
log(it)
}
}.catch { throwable ->
if (throwable is CacheMissException) {
log(throwable.message.toString())
if (it.exception is CacheMissException) {
log(it.exception!!.message.toString())
}
throw throwable
}
}
}
}
Loading