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

[apollo-tooling] bump bootstraped version of Apollo to 4.0.0-beta.3 #5452

Merged
merged 14 commits into from
Dec 15, 2023
Merged
2 changes: 1 addition & 1 deletion gradle/libraries.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ androidx-sqlite = "2.3.1"
# This is used by the gradle integration tests to get the artifacts locally
apollo = "4.0.0-beta.4-SNAPSHOT"
# Used by the apollo-tooling project which uses a published version of Apollo
apollo-published = "4.0.0-beta.2"
apollo-published = "4.0.0-beta.3"
cache = "2.0.2"
# See https://developer.android.com/jetpack/androidx/releases/compose-kotlin
compose-compiler = "1.5.5-dev-k2.0.0-Beta1-06b8ae672a4"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ class ApolloWebSocketClosedException(
/**
* The response was received but the response code was not 200
*
* @param statusCode: the HTTP status code
* @param headers: the HTTP headers
* @param body: the HTTP error body. By default, [body] is always null. You can opt-in [exposeHttpErrorBody] in [HttpNetworkTransport]
* @param statusCode the HTTP status code
* @param headers the HTTP headers
* @param body the HTTP error body. By default, [body] is always null. You can opt-in [HttpNetworkTransport.httpExposeErrorBody]
* if you need it. If you're doing this, you **must** call [BufferedSource.close] on [body] to avoid sockets and other resources leaking.
*/
class ApolloHttpException(
Expand Down Expand Up @@ -101,7 +101,7 @@ class JsonDataException(message: String) : ApolloException(message)
*/
class ApolloParseException(message: String? = null, cause: Throwable? = null) : ApolloException(message = message, cause = cause)

class ApolloGraphQLException(val error: Error): ApolloException("GraphQL error") {
class ApolloGraphQLException(val error: Error): ApolloException("GraphQL error: '${error.message}'") {
constructor(errors: List<Error>): this(errors.first())

@Deprecated("Use error instead", level = DeprecationLevel.ERROR)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
type Query {
apolloClients: [ApolloClient!]!
"""
Returns null if an ApolloClient with the given id is not found.
"""
apolloClient(id: ID!): ApolloClient
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
extend schema @link(url: "https://specs.apollo.dev/nullability/v0.1", import: ["@catch", "CatchTo"])
extend schema @catch(to: THROW)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
extend schema @link(url: "https://specs.apollo.dev/nullability/v0.1", import: ["@semanticNonNull", "@catch", "CatchTo"])
extend schema @catch(to: THROW)

extend type Service @semanticNonNull(field: "statsWindow")
extend type ServiceMutation @semanticNonNull(field: "registerOperationsWithResponse")
extend type ServiceStatsWindow @semanticNonNull(field: "fieldLatencies")
extend type RegisterOperationsMutationResponse @semanticNonNull(field: "invalidOperations")
# Not sure if errors can be null or not
# extend type InvalidOperation @semanticNonNull(field: "errors")
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
extend schema @link(url: "https://specs.apollo.dev/nullability/v0.1", import: ["@semanticNonNull", "@catch", "CatchTo"])
extend schema @catch(to: THROW)

extend type GraphMutation @semanticNonNull(field: "uploadSchema")
extend type GraphMutation @semanticNonNull(field: "publishSubgraph")
extend type GraphVariant @semanticNonNull(field: "latestPublication")
extend type SchemaPublication @semanticNonNull(field: "schema")
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.apollographql.apollo3.tooling

import com.apollographql.apollo3.annotations.ApolloExperimental
import com.apollographql.apollo3.exception.ApolloGraphQLException
import com.apollographql.apollo3.exception.ApolloHttpException
import com.apollographql.apollo3.tooling.platformapi.internal.FieldLatenciesQuery
import java.time.Instant

Expand Down Expand Up @@ -32,42 +30,27 @@ object FieldInsights {
percentile = percentile,
)
).execute()

val data = response.data
return when {
data == null -> {
val cause = when (val e = response.exception!!) {
is ApolloHttpException -> {
val body = e.body?.use { it.readUtf8() } ?: ""
Exception("Cannot fetch field latencies: (code: ${e.statusCode})\n$body", e)
}

is ApolloGraphQLException -> {
Exception("Cannot fetch field latencies: ${e.errors.joinToString { it.message }}")
}

else -> {
Exception("Cannot fetch field latencies: ${e.message}", e)
}
}
FieldLatenciesResult.Error(cause = cause)
}
if (data == null) {
return FieldLatenciesResult.Error(cause = response.toException("Cannot fetch field latencies"))
}

data.service == null && response.hasErrors() -> {
FieldLatenciesResult.Error(cause = Exception("Cannot fetch field latencies: ${response.errors!!.joinToString { it.message }}"))
}
val service = data.service
if (service == null) {
return FieldLatenciesResult.Error(cause = Exception("Cannot find service $serviceId: ${response.errors?.joinToString { it.message }}}"))
martinbonnin marked this conversation as resolved.
Show resolved Hide resolved
}

else -> {
FieldLatencies(fieldLatencies = data.service?.statsWindow?.fieldLatencies?.mapNotNull {
val parentType = it.groupBy.parentType ?: return@mapNotNull null
val fieldName = it.groupBy.fieldName ?: return@mapNotNull null
val durationMs = it.metrics.fieldHistogram.durationMs ?: return@mapNotNull null
FieldLatencies.FieldLatency(
parentType = parentType,
fieldName = fieldName,
durationMs = durationMs
)
} ?: emptyList())
}
return FieldLatencies(fieldLatencies = service.statsWindow.fieldLatencies.mapNotNull {
val parentType = it.groupBy.parentType ?: return@mapNotNull null
val fieldName = it.groupBy.fieldName ?: return@mapNotNull null
val durationMs = it.metrics.fieldHistogram.durationMs ?: return@mapNotNull null
FieldLatencies.FieldLatency(
parentType = parentType,
fieldName = fieldName,
durationMs = durationMs
)
})
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,18 @@ class PersistedQuery(
)

sealed interface PublishOperationsResult
object GraphNotFound: PublishOperationsResult
class PermissionError(val message: String): PublishOperationsResult
class CannotModifyOperationBody(val message: String): PublishOperationsResult
class PublishOperationsSuccess(val added: Int, val removed: Int, val identical: Int, val updated: Int, val unaffected: Int, val name: String, val revision: Int) : PublishOperationsResult
object GraphNotFound : PublishOperationsResult
class PermissionError(val message: String) : PublishOperationsResult
class CannotModifyOperationBody(val message: String) : PublishOperationsResult
class PublishOperationsSuccess(
val added: Int,
val removed: Int,
val identical: Int,
val updated: Int,
val unaffected: Int,
val name: String,
val revision: Int,
) : PublishOperationsResult

@ApolloExperimental
fun publishOperations(
Expand All @@ -38,11 +46,15 @@ fun publishOperations(
.execute()
}

val graph1 = response.dataOrThrow().graph
val data = response.data
if (data == null) {
throw response.toException("Cannot publish operations")
}

val graph1 = data.graph
if (graph1 == null) {
return GraphNotFound
}

val ops = graph1.persistedQueryList.publishOperations
return when {
ops.onPublishOperationsResult != null -> {
Expand All @@ -57,12 +69,16 @@ fun publishOperations(
ops.onPublishOperationsResult.build.revision
)
}

ops.onPermissionError != null -> {
PermissionError(ops.onPermissionError.message)
}

ops.onCannotModifyOperationBodyError != null -> {
CannotModifyOperationBody(ops.onCannotModifyOperationBodyError.message)
}
else -> error("")

else -> error("Unknown ops: ${ops.__typename}")
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ import com.apollographql.apollo3.ast.transform
import com.apollographql.apollo3.compiler.APOLLO_VERSION
import com.apollographql.apollo3.compiler.OperationIdGenerator
import com.apollographql.apollo3.compiler.operationoutput.OperationOutput
import com.apollographql.apollo3.exception.ApolloGraphQLException
import com.apollographql.apollo3.exception.ApolloHttpException
import com.apollographql.apollo3.tooling.platformapi.internal.RegisterOperationsMutation
import com.apollographql.apollo3.tooling.platformapi.internal.type.RegisteredClientIdentityInput
import com.apollographql.apollo3.tooling.platformapi.internal.type.RegisteredOperationInput
Expand Down Expand Up @@ -256,29 +254,21 @@ object RegisterOperations {
val response = runBlocking { call.execute() }
val data = response.data
if (data == null) {
when (val e = response.exception!!) {
is ApolloHttpException -> {
val body = e.body?.use { it.readUtf8() } ?: ""
throw Exception("Cannot push operations: (code: ${e.statusCode})\n$body", e)
}
throw response.toException("Cannot push operations")
}

is ApolloGraphQLException -> {
throw Exception("Cannot push operations: ${e.errors.joinToString { it.message }}")
}
val service = data.service
if (service == null) {
throw Exception("Cannot push operations: cannot find service '$graphID': ${response.errors?.joinToString { it.message }}")
}

else -> {
throw Exception("Cannot push operations: ${e.message}", e)
}
}
} else {
val errors = data.service?.registerOperationsWithResponse?.invalidOperations?.flatMap {
it.errors ?: emptyList()
} ?: emptyList()
val errors = data.service.registerOperationsWithResponse.invalidOperations.flatMap {
it.errors ?: emptyList()
}

check(errors.isEmpty()) {
"Cannot push operations:\n${errors.joinToString("\n")}"
}
println("Operations pushed successfully")
if (errors.isNotEmpty()) {
throw Exception("Cannot push operations:\n${errors.joinToString("\n")}")
}
println("Operations pushed successfully")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.apollographql.apollo3.ast.toFullSchemaGQLDocument
import com.apollographql.apollo3.ast.toGQLDocument
import com.apollographql.apollo3.ast.toSDL
import com.apollographql.apollo3.ast.toUtf8
import com.apollographql.apollo3.exception.ApolloHttpException
import com.apollographql.apollo3.network.okHttpClient
import com.apollographql.apollo3.tooling.SchemaHelper.reworkFullTypeFragment
import com.apollographql.apollo3.tooling.SchemaHelper.reworkInputValueFragment
Expand Down Expand Up @@ -166,21 +167,27 @@ object SchemaDownloader {
val apolloClient = ApolloClient.Builder()
.serverUrl(endpoint)
.okHttpClient(SchemaHelper.newOkHttpClient(insecure))
.httpExposeErrorBody(true)
.build()
val response = runBlocking {
apolloClient.query(DownloadSchemaQuery(graphID = graph, variant = variant))
.httpHeaders(headers.map { HttpHeader(it.key, it.value) } + HttpHeader("x-api-key", key))
.execute()
}
if (response.exception != null) throw response.exception!!
if (response.errors?.isNotEmpty() == true) {
throw Exception("Cannot retrieve document from $endpoint: ${response.errors!!.joinToString { it.message }}\nCheck graph id and variant")
val data = response.data

if (data == null) {
throw response.toException("Cannot download schema")
}

if (data.graph == null) {
throw Exception("Cannot retrieve graph '$graph': ${response.errors?.joinToString { it.message }}")
}
val document = response.data?.graph?.variant?.latestPublication?.schema?.document
check(document != null) {
"Cannot retrieve document from $endpoint\nCheck graph id and variant"

if (data.graph.variant == null) {
throw Exception("Cannot retrieve variant '$variant': ${response.errors?.joinToString { it.message }}")
}
return document
return data.graph.variant.latestPublication.schema.document
}

inline fun <reified T> Any?.cast() = this as? T
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import com.apollographql.apollo3.ast.GQLDefinition
import com.apollographql.apollo3.ast.GQLField
import com.apollographql.apollo3.ast.GQLFragmentDefinition
import com.apollographql.apollo3.ast.GQLOperationDefinition
import com.apollographql.apollo3.exception.ApolloHttpException
import com.apollographql.apollo3.network.http.DefaultHttpEngine
import com.apollographql.apollo3.network.okHttpClient
import com.apollographql.apollo3.tooling.GraphQLFeature.*
Expand Down Expand Up @@ -82,17 +81,12 @@ internal object SchemaHelper {
.httpHeaders(headers.map { HttpHeader(it.key, it.value) })
.execute()
}
response.exception?.let { e ->
if (e is ApolloHttpException) {
val body = e.body?.use { it.readUtf8() } ?: ""
throw Exception("Cannot execute pre-introspection query from $endpoint: (code: ${e.statusCode})\n$body", e)
}
throw e
}
if (response.errors?.isNotEmpty() == true) {
throw Exception("Cannot execute pre-introspection query from $endpoint: ${response.errors!!.joinToString { it.message }}")
val data = response.data
if (data == null) {
throw response.toException("Cannot execute pre-introspection query from $endpoint")
}
return response.data!!

return data
}

internal fun executeIntrospectionQuery(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package com.apollographql.apollo3.tooling
import com.apollographql.apollo3.ApolloClient
import com.apollographql.apollo3.annotations.ApolloExperimental
import com.apollographql.apollo3.api.http.HttpHeader
import com.apollographql.apollo3.exception.ApolloGraphQLException
import com.apollographql.apollo3.exception.ApolloHttpException
import com.apollographql.apollo3.tooling.platformapi.public.PublishMonolithSchemaMutation
import com.apollographql.apollo3.tooling.platformapi.public.PublishSubgraphSchemaMutation
import kotlinx.coroutines.runBlocking
Expand Down Expand Up @@ -68,27 +66,18 @@ object SchemaUploader {
val response = runBlocking { call.execute() }
val data = response.data
if (data == null) {
when (val e = response.exception!!) {
is ApolloHttpException -> {
val body = e.body?.use { it.readUtf8() } ?: ""
throw Exception("Cannot upload schema: (code: ${e.statusCode})\n$body", e)
}
throw response.toException("Cannot upload schema")
}

is ApolloGraphQLException -> {
throw Exception("Cannot upload schema: ${e.errors.joinToString { it.message }}")
}
if (data.graph == null) {
throw Exception("Cannot retrieve graph '$graphID': ${response.errors?.joinToString { it.message }}")
}

else -> {
throw Exception("Cannot upload schema: ${e.message}", e)
}
}
} else {
val code = data.graph?.uploadSchema?.code
val message = data.graph?.uploadSchema?.message
val success = data.graph?.uploadSchema?.success
check(success == true) {
"Cannot upload schema (code: $code): $message"
}
val code = data.graph.uploadSchema.code
val message = data.graph.uploadSchema.message
val success = data.graph.uploadSchema.success
if (!success) {
throw Exception("Cannot upload schema (code: $code): $message")
}
}

Expand All @@ -114,25 +103,14 @@ object SchemaUploader {
val response = runBlocking { call.execute() }
val data = response.data
if (data == null) {
when (val e = response.exception!!) {
is ApolloHttpException -> {
val body = e.body?.use { it.readUtf8() } ?: ""
throw Exception("Cannot upload schema: (code: ${e.statusCode})\n$body", e)
}

is ApolloGraphQLException -> {
throw Exception("Cannot upload schema: ${e.errors.joinToString { it.message }}")
}

else -> {
throw Exception("Cannot upload schema: ${e.message}", e)
}
}
} else {
val errors = data.graph?.publishSubgraph?.errors?.filterNotNull()?.joinToString("\n") { it.code + ": " + it.message }
check(errors.isNullOrEmpty()) {
"Cannot upload schema:\n$errors"
}
throw response.toException("Cannot upload schema")
}
if (data.graph == null) {
throw Exception("Cannot find graph '$graphID': ${response.errors?.joinToString { it.message }}")
}
val errors = data.graph.publishSubgraph.errors.filterNotNull().joinToString("\n") { it.code + ": " + it.message }
if (errors.isNotEmpty()) {
throw Exception("Cannot upload schema: $errors")
}
}
}