Skip to content

Commit 0460af9

Browse files
authored
Restore JsonReader state if a field throws in-flight (#6775)
* Add test for @catch + fragment * trigger a nested error * restore the JsonReader state if something throws in-flight
1 parent 4030cae commit 0460af9

File tree

5 files changed

+84
-5
lines changed

5 files changed

+84
-5
lines changed

libraries/apollo-api/src/commonMain/kotlin/com/apollographql/apollo/api/Adapters.kt

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,20 @@ class ListAdapter<T>(private val wrappedAdapter: Adapter<T>) : Adapter<List<@Jvm
3030
override fun fromJson(reader: JsonReader, customScalarAdapters: CustomScalarAdapters): List<T> {
3131
reader.beginArray()
3232
val list = mutableListOf<T>()
33-
while (reader.hasNext()) {
34-
list.add(wrappedAdapter.fromJson(reader, customScalarAdapters))
33+
try {
34+
while (reader.hasNext()) {
35+
list.add(wrappedAdapter.fromJson(reader, customScalarAdapters))
36+
}
37+
reader.endArray()
38+
return list
39+
} catch (e: ApolloGraphQLException) {
40+
// There was an error. Consume the remaining entries
41+
while (reader.hasNext()) {
42+
reader.skipValue()
43+
}
44+
reader.endArray()
45+
throw e
3546
}
36-
reader.endArray()
37-
return list
3847
}
3948

4049
override fun toJson(writer: JsonWriter, customScalarAdapters: CustomScalarAdapters, value: List<T>) {
@@ -358,8 +367,18 @@ class ObjectAdapter<T>(
358367
reader
359368
}
360369
actualReader.beginObject()
361-
return wrappedAdapter.fromJson(actualReader, customScalarAdapters).also {
370+
try {
371+
val result = wrappedAdapter.fromJson(actualReader, customScalarAdapters)
372+
actualReader.endObject()
373+
return result
374+
} catch (e: ApolloGraphQLException) {
375+
// There was an error. Consume the remaining entries of the object
376+
while (actualReader.hasNext()) {
377+
actualReader.nextName()
378+
actualReader.skipValue()
379+
}
362380
actualReader.endObject()
381+
throw e
363382
}
364383
}
365384

tests/catch/build.gradle.kts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,8 @@ apollo {
2828
srcDir("src/main/graphql/result")
2929
packageName.set("result")
3030
}
31+
service("fragments") {
32+
srcDir("src/main/graphql/fragments")
33+
packageName.set("fragments")
34+
}
3135
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
query GetFoo {
2+
foo @catch(to: RESULT) {
3+
foo {
4+
bar
5+
bar2: bar
6+
}
7+
}
8+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
extend schema @link(url: "https://specs.apollo.dev/nullability/v0.4", import: ["@semanticNonNullField", "@semanticNonNull", "@catch", "@catchByDefault"])
2+
extend schema @catchByDefault(to: THROW)
3+
4+
type Query {
5+
foo: Foo
6+
}
7+
8+
type Foo {
9+
bar: Int
10+
foo: Foo
11+
}
12+
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package test
2+
3+
import com.apollographql.apollo.api.FieldResult
4+
import com.apollographql.apollo.api.graphQLErrorOrNull
5+
import fragments.GetFooQuery
6+
import kotlin.test.Test
7+
import kotlin.test.assertEquals
8+
import kotlin.test.assertIs
9+
10+
class FragmentTest {
11+
@Test
12+
fun test() {
13+
// language=json
14+
val json = """
15+
{
16+
"errors": [
17+
{ "message": "Cannot return null for bar", "path": ["foo", "foo", "bar"] }
18+
],
19+
"data": {
20+
"foo": {
21+
"foo": {
22+
"bar": null,
23+
"bar2": 42
24+
}
25+
}
26+
}
27+
}
28+
""".trimIndent()
29+
30+
val response = GetFooQuery().parseResponse(json)
31+
response.data?.foo.apply {
32+
assertIs<FieldResult.Failure>(this)
33+
assertEquals("Cannot return null for bar", this.graphQLErrorOrNull()?.message)
34+
}
35+
}
36+
}

0 commit comments

Comments
 (0)