github apollographql/apollo-kotlin v3.0.0-beta01

latest releases: v4.0.0, v4.0.0-rc.2, v3.8.5...
2 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 !๐Ÿ’œ

โœจ[new] JavaScript runtime and cache support (#3208)

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:

  • SQLite is not supported yet (see #3442)
  • WebSocket are not supported yet (see #3443)

Contributions are very welcome, feel free to reach out on the kotlin lang slack to get started!

โœจ[new] Test Builders API (#3415)

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!

โœจ๐Ÿšงโœจ [new and breaking] Version2 compatibility

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.

๐Ÿšง[breaking] ApolloClient and ApolloRequest Builder APIs

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()

Websocket updates

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()

๐Ÿ‘ท All Changes

New Contributors

Full Changelog: v3.0.0-alpha07...v3.0.0-beta01

Don't miss a new apollo-kotlin release

NewReleases is sending notifications on new releases.