Β A strongly-typed, caching GraphQL client for the JVM, Android, and Kotlin multiplatform.
MIT License
Bot releases are visible (Hide)
3.0.0-beta03
is a hotfix release to fix an issue where the SQLite cache could trigger SQLiteDatabaseLockedException
under load (#3503). If you're using the SQLite cache, we strongly recommend updating.
This version introduces fluent APIs on operations, more multiplatform targets, more compatibility helpers
to ease transition from v2.x, and other fixes.
The API to execute operations now uses the Fluent style, where you can chain method calls together. The ApolloClient
query
, mutate
and subscribe
methods now return an ApolloCall
that can be configured, and on which you can call execute
to execute the operation.
Before:
val request = ApolloRequest.Builder(HeroQuery()).fetchPolicy(FetchPolicy.NetworkOnly).build()
val response = apolloClient.query(request)
After (fluent):
val response = apolloClient.query(HeroQuery())
.fetchPolicy(FetchPolicy.NetworkOnly)
.execute()
If you were using cacheAndNetwork
, it's now executeCacheAndNetwork
:
// Before
apolloClient.cacheAndNetwork(query)
// After
apolloClient.query(query).executeCacheAndNetwork()
This release adds support for these new targets:
macosArm64
iosArm64
iosSimulatorArm64
watchosArm64
watchosSimulatorArm64
tvosArm64
tvosX64
tvosSimulatorArm64
Additionally, apollo-api
(models) is now compiled for linuxX64
. Follow this issue for updates on this - and contributions on this area are welcome!
When using the responseBased codegen, now interfaces will be generated as sealed
when possible.
Because sealed interfaces are only available since Kotlin 1.5, a new Gradle option languageVersion
has been introduced to control this behavior (and potentially future language features used by the codegen).
To ease transition from 2.x, this release provides:
CustomTypeAdapter
that can be used for custom scalars in the same way as in 2.xInput
helper that will map to 3.x Optional
automaticallyThese helpers are deprecated and are to be used only as a temporary measure - they will be removed in a future version.
Thanks to @davidec-twinlogix, @pauldavies83 @nachtien and @Pitel for their awesome contributions!
Published by martinbonnin almost 3 years ago
Version 3.0.0-beta01
is the first Beta release for Apollo Android 3 π. While there are no API stability guarantees just yet, 3.0.0-beta01
introduces binary compatibility validation to monitor the breaking changes and they should happen less frequently from now on.
One important API change in 3.0.0-beta01
is the change from with-ers to Builders. It also has a useVersion2Compat Gradle property to ease the transition from 2.x.
In addition, 3.0.0-beta01
introduces JavaScript runtime and cache support and new Test Builders APIs to generate fake data models.
π Many thanks to @Pitel and @dchappelle for the awesome additions to this release !π
Version 3.0.0-beta01
has support for JavaScript targets courtesy of @Pitel. It contains both IR and LEGACY artifacts. To use it in your builds, add apollo-runtime
and apollo-normalized-cache
dependencies to your build.gradle[.kts]
:
kotlin {
js(IR) { // or js(LEGACY)
sourceSets {
val commonMain by getting {
// To use HTTP and runtime
implementation("com.apollographql.apollo3:apollo-runtime:3.0.0-beta01")
// To use in-memory cache
implementation("com.apollographql.apollo3:apollo-normalized-cache:3.0.0-beta01")
}
}
}
}
This is everything needed. All the APIs work the same as their equivalent JVM/native ones.
Two caveats:
Contributions are very welcome, feel free to reach out on the kotlin lang slack to get started!
You can now opt-in generation of Test Builders that make it easier to build fake models for your operations. Test Builders allow to generate fake data using a type safe DSL and provides mock values for fields so that you don't have to specify them all.
To enable Test Builders, add the below to your Gradle scripts:
apollo {
generateTestBuilders.set(true)
}
This will generate builders and add them to your test sourceSets. You can use them to generate fake data:
// Import the generated TestBuilder
import com.example.test.SimpleQuery_TestBuilder.Data
@Test
fun test() {
// Data is an extension function that will build a SimpleQuery.Data model
val data = SimpleQuery.Data {
// Specify values for fields that you want to control
hero = droidHero {
name = "R2D2"
friends = listOf(
friend {
name = "Luke"
}
)
// leave other fields untouched, and they will be returned with mocked data
// planet = ...
}
}
// Use the returned data
}
You can control the returned mock data using the TestResolver API:
val myTestResolver = object: DefaultTestResolver() {
fun resolveInt(path: List<Any>): Int {
// Always return 42 in fake data for Int fields
return 42
}
}
val data = SimpleQuery.Data(myTestResolver) {}
// Yay, now every Int field in `data` is 42!
3.0.0-beta01
introduces new Gradle options for better compatibility with versions 2. Most of the changes in this section can be reverted through configuration options but some had breaking side effects like valueOf
being renamed to safeValueOf
for enums.
sealedClassesForEnumsMatching
allows generating Kotlin enums for GraphQL enums.Apollo 3.x generates sealed classes for Kotlin enums. As paradoxical as it may seem, sealed classes a better representation of GraphQL enums because they allow to expose the rawValue
of new enums that are not know at compile time. Sealed classes can also handle when
exhaustivity just like Kotlin enums and are generally more flexible. Using them may change the calling code though so as a temporary migration helper, you can now fallback to enum like in 2.x by setting sealedClassesForEnumsMatching
to an empty list instead of the default listOf(".*")
:
apollo {
sealedClassesForEnumsMatching.set(emptyList())
}
One side effect of this change is that the generated MySealedClass.valueOf()
has been renamed to MySealedClass.safeValueOf()
.
generateOptionalOperationVariables
allows wrapping your variables in Optional<>
.By default Apollo Android 3 skips the Optional<>
wrapper for nullable variables. This simplifies the call site in the vast majority of cases where the variable is actually sent alongside the query.
There might be some rare occasions where you want to be able to omit a variable. For these cases, you can add an @optional
directive:
# a query that allows omitting before and/or after for bi-directional pagination
query MyQuery($before: String @optional, $after: String @optional) {
items {
title
}
}
If you have a lot of those queries, or if you prefer the 2.x behaviour, you can now opt-out globally:
apollo {
generateOptionalOperationVariables.set(true)
}
codegenModels
defaults to "operationBased"
3.0.0-beta01
now defaults to "operationBased"
models. "operationBased"
models match your GraphQL operations 1:1 and skip the extra .fragment
synthetic fields that are present in "compat"
models. Because they are simpler to understand, generate and execute, they are now the default. You can revert to "compat"
codegen with the codegenModels
Gradle option:
apollo {
codegenModels.set(MODELS_COMPAT)
}
useVersion2Compat()
For all these options, you can now fallback to the 2.x behaviour with useVersion2Compat()
. This is a shorthand function that configures the above options to match the 2.x behaviour. useVersion2Compat
is a helper to facilitate the migration and will be removed in a future update.
Following the with-er vs Builder vs DSL RFC, we decided to move the main APIs to Builders. Builders are widely accepted, battle proven APIs that play nicely with Java and will make it easier to maintain Apollo Android in the long run.
While this beta-01
release keeps the with-ers
, they will be removed before Apollo Android 3 goes stable so now is a good time to update.
To build an ApolloClient
:
// Replace
val apolloClient = ApolloClient("https://com.example/graphql")
.withNormalizedCache(normalizedCacheFactory)
// With
val apolloClient = ApolloClient.Builder()
.serverUrl("https://com.example/graphql")
.normalizedCache(normalizedCacheFactory)
.build()
To build a ApolloRequest
:
// Replace
val apolloRequest = ApolloRequest(query)
.withFetchPolicy(FetchPolicy.CacheFirst)
// With
val apolloRequest = ApolloRequest.Builder(query)
.fetchPolicy(FetchPolicy.CacheFirst)
.build()
The WebSocket code has been revamped to support client-initiated ping-pong for graphql-ws as well as a better separation between common code and protocol specific code.
A side effect is that WebSocket protocols are now configured using a WsProtocol.Factory:
// Replace
val apolloClient = ApolloClient(
networkTransport = WebSocketNetworkTransport(
serverUrl = "http://localhost:9090/graphql",
protocol = GraphQLWsProtocol()
)
)
// With
val apolloClient = ApolloClient.Builder()
.networkTransport(
WebSocketNetworkTransport(
serverUrl = "http://localhost:9090/graphql",
protocolFactory = GraphQLWsProtocol.Factory()
)
)
.build()
Full Changelog: https://github.com/apollographql/apollo-android/compare/v3.0.0-alpha07...v3.0.0-beta01
Version 2.5.10
is a maintenance release with a few bugfixes, mutiny support and a new Gradle register${VariantName}ApolloOperations
task to register your operations to the Apollo registry.
π Many thanks to @ProVir, @aoudiamoncef and @jgarrow for their contributions !π
Version 2.5.10
adds support for the Mutiny reactive library.
Add the dependency:
// Mutiny support
implementation 'com.apollographql.apollo:apollo-mutiny-support:x.y.z'
And convert your ApolloCall
to a Mutiny Uni:
// Create a query object
val query = EpisodeHeroNameQuery(episode = Episode.EMPIRE.toInput())
// Directly create Uni with Kotlin extension
val uni = apolloClient.mutinyQuery(query)
Read more in the documentation
register${VariantName}ApolloOperations
(#3403)If you're using Apollo safelisting, you can now upload the transformed operations from Gradle directly. Add a registerOperations {}
block to the apollo {}
block:
apollo {
service("service") {
registerOperations {
// You can get your key from https://studio.apollographql.com/graph/$graph/settings
key.set(System.getenv("APOLLO_KEY"))
graph.set(System.getenv("APOLLO_GRAPH"))
// Use "current" by default or any other graph variant
graphVariant.set("current")
}
}
}
Then call ./gradlew registerMainServiceApolloOperations
to register your operations to the registry. The operations will be registered including the added __typename
fields that might be added during codegen.
Full Changelog: https://github.com/apollographql/apollo-android/compare/v2.5.9...v2.5.10
Version 3.0.0-alpha07
has new builtin Adapters for java.time
, better custom scalar handling for multi module projects and multiple fixes for MPP and json parsers.
π Many thanks to @ProVir, @ychescale9 and @pauldavies83 for all the feedback and investigations !π
Like there were adapters for kotlinx.datetime
, you can now use java.time
adapters from the apollo-adapters
package:
com.apollographql.apollo3.adapter.JavaInstantAdapter
com.apollographql.apollo3.adapter.JavaLocalDateAdapter
com.apollographql.apollo3.adapter.JavaLocalDateTimeAdapter
kotlinx.datetime
AdaptersTo keep things symmetrical with the java.time
adapters, the kotlinx.datetime
adapters are now named:
com.apollographql.apollo3.adapter.KotlinxInstantAdapter
com.apollographql.apollo3.adapter.KotlinxLocalDateAdapter
com.apollographql.apollo3.adapter.KotlinxLocalDateTimeAdapter
LongAdapter
package nameBecause LongAdapter
is widely used and doesn't require any additional dependencies, it is now in the builtin apollo-api package
// Replace
com.apollographql.apollo3.adapter.LongAdapter
// With
com.apollographql.apollo3.api.LongAdapter
3.0.0-alpha05
is an incremental update on top of alpha04 with a few important fixes. Many thanks to all the feedback, in particular from @rickclephas, @ProVir, @ychescale9 and @james
on the Kotlinlang slack. Thank you π!
The Kotlin Native runtime was too strict in ensuring the Continuations
were never frozen, which caused exceptions when used with coroutines-native-mt
. This check has been removed.
To ease the transition from 2.x
, clearNormalizedCache
has been added as a deprecated function and will be removed for 3.1
Because only used types are generated in alpha04, we lost the ability to compute possible types in a typesafe way. This PR re-introduces this with an opt-it generateSchema
Gradle property:
apollo {
generateSchema.set(true)
}
This will:
__Schema
class that will hold a list of all composite typesThe __Schema
class has a possibleTypes()
function that can lookup possible types from the list of types:
assertEquals(
setOf(Cat.type, Dog.type, Crocodile.type),
__Schema.possibleTypes(Animal.type).toSet()
)
For multi-project builds, custom scalar were registered twice, leading to a validation error. This is now fixed.
3.0.0-alpha04
brings Java codegen and ApolloIdlingResource in Apollo Android 3. These were the final pieces that were not ported to Apollo Android 3 yet π..
In addition, it brings some consistency improvements in the codegen/Gradle setup as well bump the max json stack size to 256 and other ergonomic improvements and fixes.
As we move towards a stable version, we'll have to settle for the current with-er
API or Builders
. Let us know what you think by letting a comment on the RFC.
Apollo Android 3 now generates Java models if the Kotlin plugin is not applied in your project. This is detected automatically and should work in the vast majority of cases. If you want to force Java codegen while still using the Kotlin plugin, you can set generateKotlinModels.set(false)
in your Gradle scripts:
apollo {
// Generate Java classes regardless of whether the Kotlin plugin is applied
generateKotlinModels.set(false)
}
Java models work like Kotlin models and use the same runtime. With the exception of default parameters, they are compatible with Kotlin operationBased
models so you can change the target language without having to update most of your code.
apollo-idling-resource is now available in Apollo Android 3. You can include it with the apollo-idling-resource
artifact:
dependencies {
testImplementation("com.apollographql.apollo3:apollo-idling-resource:$version")
}
And create an ApolloClient
that will update the IdlingResource
:
val idlingResource = ApolloIdlingResource("test")
val apolloClient = ApolloClient("https://...")
.withIdlingResource(idlingResource)
valueOf
for enumsMany thanks to @kubode for the contribution π
For GraphQL enums generated as sealed class, you can now call valueOf
to parse a String to a given enum value (or Unknown__ if unknown):
Given the below enum:
enum Direction {
NORTH,
EAST,
SOUTH,
WEST
}
You can use:
assertEquals(Direction.NORTH, Direction.valueOf("NORTH"))
assertEquals(Direction.Unknown__("NORTH-WEST"), Direction.valueOf("NORTH-WEST"))
ApolloNetworkError
Many thanks to @ProVir for the help getting this done π
When something wrong happens during a network request, the runtime will throw a ApolloNetworkError
exception. You can now access the underlying platform error with ApolloNetworkError.platformCause
:
// On iOS you can cast to NSError
try {
apolloClient.query(query)
} catch (e: ApolloNetworkError) {
when ((e.platformCause as NSError?)?.domain) {
NSURLErrorDomain -> // handle NSURLErrorDomain errors ...
}
}
// On Android/JVM, platformCause is the same Throwable as Cause:
try {
apolloClient.query(query)
} catch (e: ApolloNetworkError) {
when (e.cause) {
is UnknownHostException -> // handle UnknownHostException errors ...
}
}
Because the default of an empty package name creates issues with kapt, it is now mandatory to set the package name of generated models:
apollo {
// Use the same packageName for all generated models
packageName.set("com.example")
// Or use a package name derived from the file location
packageNamesFromFilePaths()
}
For consistency, and in order to support multi-modules scenarios where some types are only generated in some modules, custom scalars, object and interface types are now generated as top-level classes in the .type
package name, like input objects and enums instead of being wrapped in a Types
object. Each schema type has a static type: CompiledType
property so you can access the type name in a type safe way.
// Replace
Types.Launch.name
// With
Launch.type.name
If you were using generated CustomScalarType
instances to register your custom scalar adapters, these are moved to the top level as well:
// Replace
ApolloClient("https://").withCustomScalarAdapter(Types.GeoPoint, geoPointAdapter)
// With
ApolloClient("https://").withCustomScalarAdapter(GeoPoint.type, geoPointAdapter)
DefaultHttpRequestComposerParams
Because DefaultHttpRequestComposerParams
was setting multiple parameters at the same time (HTTP headers, method, etc..), setting one of them would overwrite a default set on the client. Instead of using DefaultHttpRequestComposerParams
, set parameters individually:
apolloClient.withHttpHeader("name", "value")
apolloRequest.withHttpHeader("otherName", "otherValue")
valueOf
to the enum types (#3328)3.0.0-alpha03
is a release with a bunch of bugfixes and documentation fixes.
The Kdoc for the current dev-3.x
version is now available at: https://apollographql.github.io/apollo-android/kdoc/
Many thanks to @dchapelle for the work on WebSockets and @PHPirates and @omaksymov for the documentation fixes!
This version reworks the CacheResolver
API to hopefully clarify its usage as well as allow more advanced use cases if needed.
ObjectIdGenerator
and CacheResolver
APIsThis version splits the CacheResolver
API in two distinct parts:
ObjectIdGenerator.cacheKeyForObject
CacheResolver.resolveField
CacheKey
for objects but it can also be any other data if needed. In that respect, it's closer to a resolver as might be found in apollo-server
Previously, both methods were in CacheResolver
even if under the hood, the code path were very different. By separating them, it makes it explicit and also makes it possible to only implement one of them.
Note: In general, prefer using @typePolicy
and @fieldPolicy
that provide a declarative/easier way to manage normalization and resolution.
ObjectIdGenerator
is usually the most common one. It gives objects a unique id:
type Product {
uid: String!
name: String!
price: Float!
}
// An ObjectIdGenerator that uses the "uid" property if it exists
object UidObjectIdGenerator : ObjectIdGenerator {
override fun cacheKeyForObject(obj: Map<String, Any?>, context: ObjectIdGeneratorContext): CacheKey? {
val typename = obj["__typename"]?.toString()
val uid = obj["uid"]?.toString()
return if (typename != null && uid != null) {
CacheKey.from(typename, listOf(uid))
} else {
null
}
}
}
CacheResolver
allows resolving a specific field from a query:
query GetProduct($uid: String!) {
product(uid: $uid) {
uid
name
price
Β }
}
object UidCacheResolver: CacheResolver {
override fun resolveField(field: CompiledField, variables: Executable.Variables, parent: Map<String, Any?>, parentId: String): Any? {
var type = field.type
if (type is CompiledNotNullType) {
type = type.ofType
}
if (type !is ObjectType) {
// This only works for concrete types
return MapCacheResolver.resolveField(field, variables, parent, parentId)
}
val uid = field.resolveArgument("uid", variables)?.toString()
if (uid != null) {
return CacheKey.from(type.name, listOf(uid))
}
// Always fallback to the default resolver
return MapCacheResolver.resolveField(field, variables, parent, parentId)
}
}
This version is the first alpha on the road to a 3.0.0
release!
Apollo Android 3 rewrites a lot of the internals to be Kotlin first and support a multiplatform cache. It also has performance improvements, new codegen options, support for multiple client directives and much more!
This document lists the most important changes. For more details, consult the preliminary docs and the migration guide.
This is a big release and the code is typically less mature than in the main
branch. Please report any issue, we'll fix them urgently. You can also reach out in kotlinlang's #apollo-android slack channel for more general discussions.
This version is 100% written in Kotlin, generates Kotlin models by default and exposes Kotlin first APIs.
Using Kotlin default parameters, Builders
are removed:
import com.apollographql.apollo3.ApolloClient
val apolloClient = ApolloClient("https://com.example/graphql")
Queries are suspend fun
, Subscriptions are Flow<Response<D>>
:
val response = apolloClient.query(MyQuery())
// do something with response
apolloClient.subscribe(MySubscription()).collect { response ->
// react to changes in your backend
}
Java codegen is not working but will be added in a future update. For details and updates, see this GitHub issue
This version unifies apollo-runtime
and apollo-runtime-kotlin
. You can now use apollo-runtime
for both the JVM and iOS/MacOS:
kotlin {
sourceSets {
val commonMain by getting {
dependencies {
implementation("com.apollographql.apollo3:apollo-runtime:3.0.0-alpha01")
}
}
}
}
The normalized cache is multiplatform too and both apollo-normalized-cache
(for memory cache) and apollo-normalized-cache-sqlite
(for persistent cache) can be added to the commonMain
sourceSet.
The In-Memory cache uses a custom LruCache that supports maxSize
and weighter
options. The SQLite cache uses SQLDelight to support both JVM and native targets.
val apolloClient = ApolloClient("https://com.example/graphql")
.withNormalizedCache(MemoryCacheFactory(maxSize = 1024 * 1024))
val apolloRequest = ApolloRequest(GetHeroQuery()).withFetchPolicy(FetchPolicy.CacheFirst)
val apolloResponse = apolloClient.query(apolloRequest)
Current feature matrix:
JVM | iOS/MacOS | JS | |
---|---|---|---|
apollo-api (models) | β | β | β |
apollo-runtime (network, query batching, apq, ...) | β | β | π« |
apollo-normalized-cache | β | β | π« |
apollo-normalized-cache-sqlite | β | β | π« |
apollo-http-cache | β | π« | π« |
SQLite batching batches SQL requests instead of executing them sequentially. This can speed up reading a complex query by a factor 2x+ (benchmarks). This is especially true for queries that contain lists:
{
"data": {
"launches": {
"launches": [
{
"id": "0",
"site": "CCAFS SLC 40"
},
...
{
"id": "99",
"site": "CCBGS 80"
}
]
}
}
}
Reading the above data from the cache would take 103 SQL queries with Apollo Android 2 (1 for the root, 1 for data
, 1 for launches
, 1 for each launch). Apollo Android 3 uses 4 SQL queries, executing all the launches at the same time.
When it's possible, the parsers create the models as they read bytes from the network. By amortizing parsing during IO, the latency is smaller leading to faster UIs. It's not always possible though. At the moment, the parsers fall back to buffering when fragments are encountered because fragments may contain merged fields that need to rewind in the json stream:
{
hero {
friend {
name
}
... on Droid {
# friend is a merged field which Apollo Android needs to read twice
friend {
id
}
}
}
}
A future version might be more granular and only fallback to buffering when merged fields are actually used.
The codegen has been rethought with the goal of supporting Fragments as Interfaces.
To say it turned out to be a complex feature would be a understatement. GraphQL is a very rich language and supporting all the edge cases that come with polymorphism, @include
/@skip
directives and more would not only be very difficult to implement but also generate very complex code (see 3144). While fragments as interfaces are not enabled by default, the new codegen allows to experiment with different options and features.
The codegen supports 3 modes:
compat
(default) uses the same structure as 2.x.operationBased
generates simpler models that map the GraphQL operation 1:1.responseBased
generates more complex models that map the Sson response 1:1.responseBased
models will generate fragments as interfaces and can always use streaming parsers. They do not support @include
/@skip
directives on fragments and will generate sensibly more complex code.
Read Codegen.md for more details about the different codegen modes.
To change the codegen mode, add this to your build.gradle[.kts]
:
apollo {
codegenModels.set("responseBased") // or "operationBased", or "compat"
}
The codegen now generates a list of the different types in the schema.
You can use these to get the different __typename
in a type-safe way:
val typename = Types.Human.name
// "Human"
or find the possible types of a given interface:
val possibleTypes = Types.possibleTypes(Types.Character)
// listOf(Types.Human, Types.Droid)
This version includes apollo-graphql-ast
that can parse GraphQL documents into an AST. Use it to analyze/modify GraphQL files:
file.parseAsGQLDocument()
.definitions
.filterIsInstance<GQLOperationDefinition>
.forEach {
println("File $file.name contains operation '$it.name'")
}
@nonnull
turns nullable GraphQL fields into non-null Kotlin properties. Use them if such a field being null is generally the result of a larger error that you want to catch in a central place (more in docs):
query GetHero {
# data.hero will be non-null
hero @nonnull {
name
}
}
Apollo Android distinguishes between:
null
or notThe GraphQL spec makes non-nullable variables optional. A query like this:
query GetHero($id: String) {
hero(id: $id) {
name
}
}
will be generated with an optional id
constructor parameter:
class GetHeroQuery(val id: Optional<String?> = Optional.Absent)
While this is correct, this is also cumbersome. If you added the id
variable in the first place, there is a very high chance you want to use it. Apollo Android 3 makes variables non-optional by default (but possibly nullable):
class GetHeroQuery(val id: String?)
If for some reason, you need to be able to omit the variable, you can opt-in optional again:
# id will be an optional constructor parameter
query GetHero($id: String @optional) {
hero(id: $id) {
name
}
}
You can use @typePolicy
to tell the runtime how to compute a cache key from object fields:
extend type Book @typePolicy(keyFields: "isbn")
The above will add isbn
wherever a Book
is queried and use "Book:$isbn"
as a cache key.
Since this works at the schema level, you can either modify your source schema or add an extra extra.graphqls
file next to it that will be parsed at the same time.
Symmetrically from @typePolicy
, you can use @fieldPolicy
to tell the runtime how to compute a cache key from a field and query variables.
Given this schema:
type Query {
book(isbn: String!): Book
}
you can tell the runtime to use the isbn
argument as a cache key with:
extend type Query @fieldPolicy(forField: "book", keyArgs: "isbn")
This version includes an apollo-adapters
artifact that includes Adapters for common custom scalar types:
kotlinx.datetime.Instant
ISO8601 dateskotlinx.datetime.LocalDate
ISO8601 datesjava.util.Date
ISO8601 datesjava.lang.Long
com.apollographql.apollo3.BigDecimal
class holding big decimal valuesThis version comes with builtin graphql-ws
support in addition to the default graphql-transport-ws
. You can use graphql-ws
for queries and mutation in addition to subscriptions if your server supports it.
// Creates a client that will use WebSockets and `graphql-ws` for all queries/mutations/subscriptions
val apolloClient = ApolloClient(
networkTransport = WebSocketNetworkTransport(serverUrl = "wss://com.example/graphql", protocol = GraphQLWsProtocol())
)
Version 2.5.8 adds support for Query Batching thanks to the awesome work of @joaquim-verges (#3117) π as well as reactor bindings made with π by @aoudiamoncef (#3138). Thanks a lot for making Apollo Android betterοΈ!
Query batching collects multiple GraphQL queries happening in a short timeframe and sends them in a single HTTP call to a compatible server. This minimizes the number of HTTP calls, for an exemple when a new screen is displayed and multiple queries are sent at the same time.
To enable batching in your ApolloClient
:
val apolloClient = ApolloClient.builder()
.serverUrl("https://")
.batchingConfiguration(
BatchConfig(
// enable batching
batchingEnabled = true,
// check queries every 20ms
batchIntervalMs = 20,
// or send as soon as there are 10 queries queued
maxBatchSize = 10
)
)
.build()
apolloClient.startBatchPoller()
Execute your queries:
val response = apolloClient.query(MyQuery())
.toBuilder()
.canBeBatched(true)
.build()
.await()
Stop batching:
apolloClient.stopBatchPoller()
Note: Enabling query batching reduces the number of HTTP calls but increases latency. Since the Batcher is run from a timer, an otherwise fast query will have to wait for both the timer to happen, and the backend to process all the events in the batch.
Project reactor is a reactive streams implementation for building non-blocking applications on the JVM. It's often used with Spring Boot for an example.
To add to your project:
// Reactor support
implementation("com.apollographql.apollo:apollo-reactor-support:x.y.z")
The usage is very similar to the RxJava2/RxJava3 bindings:
// Create Mono from a query
val mono = apolloClient.reactorQuery(query)
// Create Flux from a subscription
val flux = apolloClient.reactorSubscribe(subscription)
For more information, refer to the documentation.
apollo-runtime
(#3117)Version 2.5.7 is built with Kotlin 1.5.0
and compatible with coroutines 1.5.0
. It also fixes a regression while parsing defaultValues with Int
values that should be coerced to Float
and allows to change the buffering of MPP subscription messages thanks to the awesome work of @joaquim-verges (#3109) and @nealsanche (#3096)
1.5.0
supportVersion 2.5.6 exposes the Gradle plugin as a fat jar to workaround a long standing issue where older versions of okio
and/or antlr
would be loaded first in the classpath and override the versions required by the plugin (See #2287, #2359, #2886, #2939, #3022).
It does so by relocating and packaging the following dependencies inside apollo-gradle-plugin.jar
:
The only functional change in this version is #3039 to include better exception messages, courtesy of @semaphore3000.
If you notice anything classloading-weird or if this doesn't work in your setup, please open an issue.
Version 2.5.5 is a maintenance release with support for ".graphqls"
files and fixes in the Json parser and HTTP cache.
.graphqls
files are now recognized as schema files (#2977)'\f'
) in json (#3006)Many thanks to @Romadro, @eduardb and @BRoy98 for their contributions!
Version 2.5.4 is a maintenance release. This version dropped Jcenter publishing and is the first one to be only available on Maven Central.
It also contains some improvements around the Gradle plugin and codegen.
checkApolloVersions
more lazy (#2935)ResponseFieldMapper
when using delegates (#2945)Many thanks to @ansman and @lorensr for their contributions!
Version 2.5.3 is a maintenance release with improvements around codegen, runtime and cache.
Version 2.5.3 adds support for GraphQL RFC 373 (interfaces implementing interfaces). This makes sure the codegen understands interfaces implementing other interfaces and can compute the fragments possible types appropriately. It doesn't change the generated code.
Version 2.5.3 changes the Content-Type
for apollo-runtime-kotlin
from "aplication/json; charset=utf-8"
to "application/json"
. This has been confusing spring servers and is the default json content type moving forward. If everything goes well, apollo-runtime
will also switch to "application/json"
in a future release. Read more in #2883. Many thanks to @vikrama for diving into this and fixing it.
Many thanks to @vikrama for fixing the content-type, to @AOrobator for making the Error
and Location
classes easier to debug, to @ansman for fixing Base64 on old Android versions, to @emmano for improving the documentation and @lwasyl for all the cache investigations!
Version 2.5.2 fixes a bunch of bugs and adds ApolloAndroidLogger
and AppSyncOperationMessageSerializer
. Huge thanks to @AdamMc331 and @ansman for their respective work on the logger and serializer π !
Note: version 2.5.2 is released from Github actions and that took a few iterations to get right. As a result, version 2.5.0 and 2.5.1 were not published and will never be.
ApolloAndroidLogger
is a logger that will send its output to Logcat. Use it to display debug information on Android devices:
ApolloClient.builder()
.logger(ApolloAndroidLogger())
[...]
.build
AppSyncOperationMessageSerializer
is a serializer that can understand the AWS AppSync message format. Pass it to your WebSocketSubscriptionTransport.Factory
:
// This example uses an API key. See the AppSync documentation for information on what to pass
val authorization = mapOf(
"host" to "example1234567890000.appsync-api.us-east-1.amazonaws.com",
"x-api-key" to "da2-12345678901234567890123456"
)
val webSocketUrl = AppSyncOperationMessageSerializer.buildWebSocketUrl(
baseWebSocketUrl = "wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql",
authorization = authorization
)
val subscriptionTransportFactory = WebSocketSubscriptionTransport.Factory(
webSocketUrl = webSocketUrl,
webSocketConnectionFactory = okHttpClient,
serializer = AppSyncOperationMessageSerializer(authorization)
)
apolloClient.builder()
.subscriptionTransportFactory(subscriptionTransportFactory)
.build()
Version 2.4.6 is a minor release with fixes around multiplatform, normalized cache and others. Many thanks to @tylerbwong and @lwasyl for their work on the metalava integration and enum serialization respectively.
[Normalized cache] Add interface for classes generated for enum types and fix sealed classes json representation (#2776)
[Multiplatform] fix NSURLSession configuration (#2777)
[Test] adding test coverage (#2770)
[Runtime] revert to okhttp 3 to support older versions of Android (#2769)
[Gradle Plugin] make convertApolloSchema never up-to-date (#2761)
[Multiplatform] Do not use Java8 Duration (#2767)
[Build scripts] Fix error.NonExistentClass in Metalava Signature Files (#2755)
[codegen] Honor packageName for schema types as well (#2759)