Apollo Kotlin - a GraphQL client that generates Kotlin and Java models from GraphQL queries.

Overview

Apollo Kotlin

GitHub license Join the community Slack CI Maven Central OSS Snapshots

Apollo Kotlin (formerly known as Apollo Android) is a GraphQL client that generates Kotlin and Java models from GraphQL queries.

Apollo Kotlin executes queries and mutations against a GraphQL server and returns results as query-specific Kotlin types. This means you don't have to deal with parsing JSON, or passing around Maps and making clients cast values to the right type manually. You also don't have to write model types yourself, because these are generated from the GraphQL definitions your UI uses.

Because generated types are query-specific, you can only access data that you actually specify as part of a query. If you don't ask for a particular field in a query, you can't access the corresponding property on the returned data structure.

This library is designed primarily with Android in mind, but you can use it in any Java/Kotlin app, including multiplatform.

Features

  • Java and Kotlin Multiplatform code generation
  • Queries, Mutations and Subscriptions
  • Reflection-free parsing
  • Normalized cache
  • Custom scalar types
  • HTTP cache
  • Auto Persisted Queries
  • Query batching
  • File uploads
  • Espresso IdlingResource
  • Fake models for tests
  • AppSync and graphql-ws websockets
  • GraphQL AST parser

Multiplatform

Apollo Kotlin is a Kotlin Multiplatform project.

Here's the current matrix of supported features per platform:

jvm Apple¹ js linuxX64
apollo-api (models)
apollo-runtime (network, query batching, apq, ...) ² 🚫
apollo-normalized-cache 🚫
apollo-adapters 🚫
apollo-normalized-cache-sqlite 🚫 🚫
apollo-http-cache 🚫 🚫 🚫

¹: Apple currently includes:

  • macosX64
  • macosArm64
  • iosArm64
  • iosX64
  • iosSimulatorArm64
  • watchosArm64
  • watchosSimulatorArm64
  • tvosArm64
  • tvosX64
  • tvosSimulatorArm64

²: WebSockets are currently not supported on js

Documentation

Check the project website for in depth documentation.

Getting started

If you are new to GraphQL, check out the tutorial that will guide you through building an Android app using Apollo, Kotlin and coroutines.

If you'd like to add Apollo Kotlin to an existing project, follow these steps:

Add the plugin to your build.gradle.kts:

plugins {
  id("com.apollographql.apollo3").version("x.y.z")
}

Add the runtime dependency:

dependencies { 
  implementation("com.apollographql.apollo3:apollo-runtime:x.y.z")
}

Set the package name to use for the generated models:

apollo {
  packageName.set("com.example")
}

Apollo Kotlin supports three types of files:

  • .graphqls schema files: describes the types in your backend using the GraphQL syntax.
  • .json schema files: describes the types in your backend using the Json syntax.
  • .graphql executable files: describes your queries and operations in the GraphQL syntax.

By default, Apollo Kotlin requires a schema in your module's src/main/graphql directory. You can download a schema using introspection with the ./gradlew downloadApolloSchema task. Sometimes introspection is disabled and you will have to ask your backend team to provide a schema. Copy this schema to your module:

cp ${schema} ${module}/src/main/graphql/ 

Write a query in a ${module}/src/main/graphql/GetRepository.graphql file:

query HeroQuery($id: String!) {
  hero(id: $id) {
    id
    name
    appearsIn
  }
}

Build your project, this will generate a HeroQuery class that you can use with an instance of ApolloClient:

  // Create a client
  val apolloClient = ApolloClient.Builder()
      .serverUrl("https://example.com/graphql")
      .build()

  // Execute your query. This will suspend until the response is received.
  val response = apolloClient.query(HeroQuery(id = "1")).execute()

  println("Hero.name=${response.data?.hero?.name}")

To learn more about other Apollo Kotlin APIs:

IntelliJ Plugin

The JS Graphql IntelliJ Plugin provides auto-completion, error highlighting, and go-to-definition functionality for your .graphql files. You can create a .graphqlconfig file to use GraphQL scratch files to work with your schema outside product code (such as to write temporary queries to test resolvers).

Releases

The latest version is Maven Central

Check the changelog for the release history.

Releases are hosted on Maven Central. The plugin is additionally hosted on the Gradle Plugin Portal

plugins {
  id("com.apollographql.apollo3").version("x.y.z")
}

repositories {
  mavenCentral()
}

dependencies {
  implementation("com.apollographql.apollo3:apollo-runtime:x.y.z")

  // optional: if you want to use the normalized cache
  implementation("com.apollographql.apollo3:apollo-normalized-cache-sqlite:x.y.z")
  // optional: if you just want the generated models and parsers and write your own HTTP code/cache code, you can remove apollo-runtime
  // and use apollo-api instead  
  implementation("com.apollographql.apollo3:apollo-api:x.y.z")
}

Snapshots

Latest development changes are available in Sonatype's snapshots repository:

repositories {
  maven { 
    url = uri("https://s01.oss.sonatype.org/content/repositories/snapshots/")
  }
}

Requirements

Some platforms have specific requirements:

  • Android API level 21+
  • JDK 8+
  • iOS 13+

For building, it requires:

  • Gradle 5.6
  • Kotlin 1.4+

Contributing

If you'd like to contribute, please see Contributing.md.

Additional resources

Who is Apollo?

Apollo builds open-source software and a graph platform to unify GraphQL across your apps and services. We help you ship faster with:

  • Apollo Studio – A free, end-to-end platform for managing your GraphQL lifecycle. Track your GraphQL schemas in a hosted registry to create a source of truth for everything in your graph. Studio provides an IDE (Apollo Explorer) so you can explore data, collaborate on queries, observe usage, and safely make schema changes.
  • Apollo Federation – The industry-standard open architecture for building a distributed graph. Use Apollo’s gateway to compose a unified graph from multiple subgraphs, determine a query plan, and route requests across your services.
  • Apollo Client – The most popular GraphQL client for the web. Apollo also builds and maintains Apollo iOS and Apollo Kotlin.
  • Apollo Server – A production-ready JavaScript GraphQL server that connects to any microservice, API, or database. Compatible with all popular JavaScript frameworks and deployable in serverless environments.

Learn how to build with Apollo

Check out the Odyssey learning platform, the perfect place to start your GraphQL journey with videos and interactive code challenges. Join the Apollo Community to interact with and get technical help from the GraphQL community.

Comments
  • Query duplication

    Query duplication

    Version

    3.7.0

    Summary

    Hello, when I click action button, network debugger shows 50 outgoing requests are sent to our server. I noticed existing issue that was closed long time ago, not sure if things have changed. https://github.com/apollographql/apollo-kotlin/issues/646

        @Inject
        @AuthenticatedClient
        internal lateinit var apolloClient: ApolloClient
    
        private fun onActionButtonClicked() {
            for (i in 1..50) {
                disposables.add(
                    apolloClient.query(
                        OffsiteQuery(
                            url = "https://thesassyowlboutique.com/products/hearts-aflutter-skort?variant=39947075715150"
                        )
                    ).fetchPolicy(FetchPolicy.CacheFirst).rxSingle()
                    // Ignore the result since this is just a prefetch
                    .subscribe(Functions.emptyConsumer(), Functions.emptyConsumer())
                )
            }
        }
    
    Screen Shot 2023-01-04 at 12 50 00 PM

    Unrelated, with our REST Retrofit Repository implementation, it only fetches from server once.

    @Inject
    lateinit var urlInfoRepository: UrlInfoRepository
    
    private fun onActionButtonClicked() {
        for (i in 1..50) {
            disposables.add(
                urlInfoRepository.getUrlInfo(
                    "https://thesassyowlboutique" +
                        ".com/products/hearts-aflutter-skort?variant=39947075715150", "1059401512322041701", null
                )
                .subscribe(Functions.emptyConsumer(), Functions.emptyConsumer())
            )
        }
    }
    
    :car: Runtime :rocket: Type: Enhancement 
    opened by ynkm169 4
  • Data builders: generate builders for unknown types

    Data builders: generate builders for unknown types

    Use case

    Currently the data builders are only generated for all types known in the schema at build time.

    When testing the case of receiving a new type (server's schema is more recent than the schema used at build time), it can be handy to also have the ability to build unknown types. With the responseBased codegen that would be the Other types of the generated sealed interfaces.

    Describe the solution you'd like

    Have the codegen generate builders for the interfaces, taking the __typename as a parameter.

    :gear: Codegen :sparkles: Type: Feature :technologist: Tests 
    opened by BoD 1
  • DiskLruCache is not main-safe - performs file i/o on the current thread.

    DiskLruCache is not main-safe - performs file i/o on the current thread.

    Version

    3.7.3

    Summary

    Currently, DiskLruCache + HttpCacheExtensions leads to an Android StrictMode DiskReadViolation (which occurs when file I/O is performed on the main thread) when entries are removed from the cache:

    Example from HttpCacheExtensions: cacheKey?.let { cachingHttpInterceptor.cache.remove(it) }

    DiskLruCache performs file I/O and therefore either needs to internally make sure this work is happening on a background thread or consumers (in this case HttpCacheExtensions) must enforce this. Neither is being done right now.

    If you don't have it set up already, would highly recommend turning on StrictMode in CI for your Android project so that you can catch these issues in testing!

    Steps to reproduce the behavior

    1. Turn on DiskLruCache.
    2. Enable Android StrictMode with disk read violations set to fatal.
    3. Make a query that will return a response with errors to trigger cache removal.
    4. See crash.

    Logs

    Process: <omitted>, PID: 19851
    java.lang.RuntimeException: StrictMode ThreadPolicy violation
            at android.os.StrictMode$AndroidBlockGuardPolicy.onThreadPolicyViolation(StrictMode.java:1875)
    	at android.os.StrictMode$AndroidBlockGuardPolicy.lambda$handleViolationWithTimingAttempt$0$android-os-StrictMode$AndroidBlockGuardPolicy(StrictMode.java:1789)
    	at android.os.StrictMode$AndroidBlockGuardPolicy$$ExternalSyntheticLambda1.run(Unknown Source:6)
    	at android.os.Handler.handleCallback(Handler.java:942)
    	at android.os.Handler.dispatchMessage(Handler.java:99)
    	at android.os.Looper.loopOnce(Looper.java:201)
    	at android.os.Looper.loop(Looper.java:288)
    	at android.app.ActivityThread.main(ActivityThread.java:7872)
    	at java.lang.reflect.Method.invoke(Native Method)
    	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
    	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
    Caused by: android.os.strictmode.DiskReadViolation
    	at android.os.StrictMode$AndroidBlockGuardPolicy.onReadFromDisk(StrictMode.java:1658)
    	at libcore.io.BlockGuardOs.open(BlockGuardOs.java:269)
    	at libcore.io.ForwardingOs.open(ForwardingOs.java:563)
    	at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:7758)
    	at libcore.io.IoBridge.open(IoBridge.java:560)
    	at java.io.FileInputStream.<init>(FileInputStream.java:160)
    	at okio.Okio__JvmOkioKt.source(JvmOkio.kt:182)
    	at okio.Okio.source(Unknown Source:1)
    	at okio.JvmSystemFileSystem.source(JvmSystemFileSystem.kt:95)
    	at com.apollographql.apollo3.cache.http.internal.DiskLruCacheKt.source(DiskLruCache.kt:1020)
    	at com.apollographql.apollo3.cache.http.internal.DiskLruCacheKt.access$source(DiskLruCache.kt:1)
    	at com.apollographql.apollo3.cache.http.internal.DiskLruCache.readJournal(DiskLruCache.kt:231)
    	at com.apollographql.apollo3.cache.http.internal.DiskLruCache.initialize(DiskLruCache.kt:208)
    	at com.apollographql.apollo3.cache.http.internal.DiskLruCache.remove(DiskLruCache.kt:545)
    	at com.apollographql.apollo3.cache.http.DiskLruHttpCache.remove(DiskLruHttpCache.kt:103)
    	at com.apollographql.apollo3.cache.http.HttpCache$httpCache$2$intercept$1$2.invokeSuspend(HttpCacheExtensions.kt:130)
    	at com.apollographql.apollo3.cache.http.HttpCache$httpCache$2$intercept$1$2.invoke(Unknown Source:8)
    	at com.apollographql.apollo3.cache.http.HttpCache$httpCache$2$intercept$1$2.invoke(Unknown Source:4)
            <rest of stack trace omitted for brevity>
    
    :bug: Type: Bug 
    opened by prashanOS 0
  • Default values for output fields

    Default values for output fields

    Use case

    Sometimes a value returned by a server is the same in the vast majority of the cases. For an example, a query like this:

    {
      users: {
        id
        role
      }
    }
    

    might return a Json like this:

    {
      users: [
        {
          "id": 0,
          "role": "ADMIN"
        },
        {
          "id": 1,
          "role": "VIEWER"
        },
        {
          "id": 2,
          "role": "VIEWER"
        },
        {
          "id": 3,
          "role": "VIEWER"
        },
        // ... more VIEWERS
      ]
    }
    

    This is verbose and makes payloads larger than they need to be

    Describe the solution you'd like

    We could specify at the schema and/or query level that a given field has a default value:

    Schema level:

    type User {
      id: ID!
      role: Role @default(value: VIEWER)
    }
    

    Query level:

    {
      users {
        id
        role @default(value: VIEWER)
      }
    }
    

    Doing this, the backend could skip the fields with the default value:

    {
      users: [
        {
          "id": 0,
          "role": "ADMIN"
        },
        {
          "id": 1
        },
        {
          "id": 2
        },
        {
          "id": 3
        },
        // ... more VIEWERS
      ]
    }
    
    :sparkles: Type: Feature 
    opened by martinbonnin 0
  • MultipartReader$Companion.readHeaders throws Unexpected header

    MultipartReader$Companion.readHeaders throws Unexpected header

    Version

    com.apollographql.apollo3: 3.7.3, graphql-yoga: 3.1.1

    Summary

    Graphql Server 3.x is returning invalid multipart response. Following header is added by the android apollo kotlin sdk which seems the sole cause:

    -H "Accept:multipart/mixed; deferSpec=20220824, application/json"

    It is clear from logs that five hyphens are appended at the end of response which making multipart rader throw exception:

    Unexpected header: -----

    Steps to reproduce the behavior

    Use any graphql query with the above version set and it will throw an error.

    It was working in android kotlin sdk 2.x

    Logs

    -29946 okhttp.OkHttpClient     staging.xxxx.app                 I  --> POST https://api.xxx-staging.live/graphql
    2022-12-22 17:13:12.382 29892-29946 okhttp.OkHttpClient     staging.xxxx.app                 I  Content-Type: application/json
    2022-12-22 17:13:12.382 29892-29946 okhttp.OkHttpClient     staging.xxxx.app                 I  Content-Length: 147
    2022-12-22 17:13:12.382 29892-29946 okhttp.OkHttpClient     staging.xxxx.app                 I  X-APOLLO-OPERATION-ID: 530c832b59f59d578fbc1e895e4ff9777ccad79dcb221af71bc961da07f3a281
    2022-12-22 17:13:12.382 29892-29946 okhttp.OkHttpClient     staging.xxxx.app                 I  X-APOLLO-OPERATION-NAME: tipItemList
    2022-12-22 17:13:12.382 29892-29946 okhttp.OkHttpClient     staging.xxxx.app                 I  Accept: multipart/mixed; deferSpec=20220824, application/json
    2022-12-22 17:13:12.383 29892-29946 okhttp.OkHttpClient     staging.xxxx.app                 I  {"operationName":"tipItemList","variables":{},"query":"query tipItemList { tipItemList { amount animation_asset_link created_at id image name } }"}
    2022-12-22 17:13:12.383 29892-29946 okhttp.OkHttpClient     staging.xxxx.app                 I  --> END POST (147-byte body)
    2022-12-22 17:13:12.816 29892-30129 okhttp.OkHttpClient     staging.xxxx.app                 I  <-- 101 Switching Protocols https://api.xxxshop-staging.live/graphql (1008ms)
    2022-12-22 17:13:12.817 29892-30129 okhttp.OkHttpClient     staging.xxxx.app                 I  Date: Thu, 22 Dec 2022 11:43:25 GMT
    2022-12-22 17:13:12.817 29892-30129 okhttp.OkHttpClient     staging.xxxx.app                 I  Connection: upgrade
    2022-12-22 17:13:12.817 29892-30129 okhttp.OkHttpClient     staging.xxxx.app                 I  Upgrade: websocket
    2022-12-22 17:13:12.817 29892-30129 okhttp.OkHttpClient     staging.xxxx.app                 I  Sec-WebSocket-Accept: Oi0sweoMmN47sd1ECsMCX4d4UE8=
    2022-12-22 17:13:12.817 29892-30129 okhttp.OkHttpClient     staging.xxxx.app                 I  Sec-WebSocket-Protocol: graphql-transport-ws
    2022-12-22 17:13:12.818 29892-30129 okhttp.OkHttpClient     staging.xxxx.app                 I  <-- END HTTP
    2022-12-22 17:13:12.860 29892-29991 EGL_emulation           staging.xxxx.app                 D  app_time_stats: avg=9.13ms min=1.55ms max=28.66ms count=62
    2022-12-22 17:13:12.891 29892-29944 okhttp.OkHttpClient     staging.xxxx.app                 I  <-- 200 https://api.xxxshop-staging.live/graphql (1194ms)
    2022-12-22 17:13:12.893 29892-29944 okhttp.OkHttpClient     staging.xxxx.app                 I  date: Thu, 22 Dec 2022 11:43:25 GMT
    2022-12-22 17:13:12.893 29892-29944 okhttp.OkHttpClient     staging.xxxx.app                 I  content-type: multipart/mixed; boundary="-"
    2022-12-22 17:13:12.893 29892-29944 okhttp.OkHttpClient     staging.xxxx.app                 I  xxx-trace-id: ead93dc49d6845bd196680ddf88506f9
    2022-12-22 17:13:12.893 29892-29944 okhttp.OkHttpClient     staging.xxxx.app                 I  access-control-allow-origin: *
    2022-12-22 17:13:12.894 29892-29944 okhttp.OkHttpClient     staging.xxxx.app                 I  ---
    2022-12-22 17:13:12.894 29892-29944 okhttp.OkHttpClient     staging.xxxx.app                 I  Content-Type: application/json; charset=utf-8
    2022-12-22 17:13:12.894 29892-29944 okhttp.OkHttpClient     staging.xxxx.app                 I  Content-Length: 776
    2022-12-22 17:13:12.894 29892-29944 okhttp.OkHttpClient     staging.xxxx.app                 I  
    2022-12-22 17:13:12.894 29892-29944 okhttp.OkHttpClient     staging.xxxx.app                 I  {"data":{"stream":{"id":1080,"title":"first testing stream","is_live":true,"likes":226,"isInWatchlist":false,"stream_recordings":null,"preview_image":"https://cdn.xxxshop.live/QPd0STKNf26mDKW4sCbO4.jpg","preview_video":null,"rtc_token":"006afd07411e1914563bbe3094f7b818518IADazGcAnvV3UhiNgi6llpXK54yopNXwAAC3wj5SaKunlkZaLZcUergdEADRzuCOXZSlYwEAAQBdlKVj","start_datetime":"2022-06-21T06:03:00.000Z","stream_slug":"stream1","watchlist_count":1,"went_live_at":"2022-09-06T04:58:12.515Z","went_offline_at":"2022-12-21T20:46:31.601Z","end_datetime":"2022-12-22T11:46:46.780Z","host":{"id":10633,"name":"Bhavin","slug":"bhavinSavsani","picture":"https://cdn.xxxshop.live/user-profile/7pjm83Bu3k_wt2FEftdCP.jpg","is_self_following":true,"nickname":"bhavinSavsani","ratings":4.3}}}}
    2022-12-22 17:13:12.894 29892-29944 okhttp.OkHttpClient     staging.xxxx.app                 I  ---
    2022-12-22 17:13:12.894 29892-29944 okhttp.OkHttpClient     staging.xxxx.app                 I  -----
    2022-12-22 17:13:12.895 29892-29944 okhttp.OkHttpClient     staging.xxxx.app                 I  <-- END HTTP (865-byte body)
    2022-12-22 17:13:12.904 29892-29892 System.err              staging.xxxx.app                 W  java.lang.IllegalStateException: Unexpected header: -----
    2022-12-22 17:13:12.905 29892-29892 System.err              staging.xxxx.app                 W  	at com.apollographql.apollo3.internal.MultipartReader$Companion.readHeaders(MultipartReader.kt:206)
    2022-12-22 17:13:12.905 29892-29892 System.err              staging.xxxx.app                 W  	at com.apollographql.apollo3.internal.MultipartReader$Companion.access$readHeaders(MultipartReader.kt:190)
    2022-12-22 17:13:12.905 29892-29892 System.err              staging.xxxx.app                 W  	at com.apollographql.apollo3.internal.MultipartReader.nextPart(MultipartReader.kt:136)
    2022-12-22 17:13:12.906 29892-29892 System.err              staging.xxxx.app                 W  	at com.apollographql.apollo3.internal.MultipartKt$multipartBodyFlow$1.invokeSuspend(multipart.kt:27)
    2022-12-22 17:13:12.906 29892-29892 System.err              staging.xxxx.app                 W  	at com.apollographql.apollo3.internal.MultipartKt$multipartBodyFlow$1.invoke(Unknown Source:8)
    2022-12-22 17:13:12.906 29892-29892 System.err              staging.xxxx.app                 W  	at com.apollographql.apollo3.internal.MultipartKt$multipartBodyFlow$1.invoke(Unknown Source:4)
    2022-12-22 17:13:12.906 29892-29892 System.err              staging.xxxx.app                 W  	at kotlinx.coroutines.flow.SafeFlow.collectSafely(Builders.kt:61)
    2022-12-22 17:13:12.907 29892-29892 System.err              staging.xxxx.app                 W  	at kotlinx.coroutines.flow.AbstractFlow.collect(Flow.kt:230)
    2022-12-22 17:13:12.907 29892-29892 System.err              staging.xxxx.app                 W  	at kotlinx.coroutines.flow.FlowKt__EmittersKt$onCompletion$$inlined$unsafeFlow$1.collect(SafeCollector.common.kt:114)
    2022-12-22 17:13:12.907 29892-29892 System.err              staging.xxxx.app                 W  	at com.apollographql.apollo3.network.http.HttpNetworkTransport$multipleResponses$$inlined$map$1.collect(SafeCollector.common.kt:113)
    2022-12-22 17:13:12.907 29892-29892 System.err              staging.xxxx.app                 W  	at com.apollographql.apollo3.network.http.HttpNetworkTransport$multipleResponses$$inlined$filterNot$1.collect(SafeCollector.common.kt:113)
    2022-12-22 17:13:12.907 29892-29892 System.err              staging.xxxx.app                 W  	at com.apollographql.apollo3.network.http.HttpNetworkTransport$execute$1$invokeSuspend$$inlined$map$1.collect(SafeCollector.common.kt:113)
    2022-12-22 17:13:12.907 29892-29892 System.err              staging.xxxx.app                 W  	at kotlinx.coroutines.flow.FlowKt__CollectKt.emitAll(Collect.kt:109)
    2022-12-22 17:13:12.907 29892-29892 System.err              staging.xxxx.app                 W  	at kotlinx.coroutines.flow.FlowKt.emitAll(Unknown Source:1)
    2022-12-22 17:13:12.907 29892-29892 System.err              staging.xxxx.app                 W  	at com.apollographql.apollo3.network.http.HttpNetworkTransport$execute$1.invokeSuspend(HttpNetworkTransport.kt:78)
    2022-12-22 17:13:12.907 29892-29892 System.err              staging.xxxx.app                 W  	at com.apollographql.apollo3.network.http.HttpNetworkTransport$execute$1.invoke(Unknown Source:8)
    2022-12-22 17:13:12.907 29892-29892 System.err              staging.xxxx.app                 W  	at com.apollographql.apollo3.network.http.HttpNetworkTransport$execute$1.invoke(Unknown Source:4)
    2022-12-22 17:13:12.907 29892-29892 System.err              staging.xxxx.app                 W  	at kotlinx.coroutines.flow.SafeFlow.collectSafely(Builders.kt:61)
    2022-12-22 17:13:12.907 29892-29892 System.err              staging.xxxx.app                 W  	at kotlinx.coroutines.flow.AbstractFlow.collect(Flow.kt:230)
    2022-12-22 17:13:12.907 29892-29892 System.err              staging.xxxx.app                 W  	at kotlinx.coroutines.flow.internal.ChannelFlowOperatorImpl.flowCollect(ChannelFlow.kt:195)
    2022-12-22 17:13:12.907 29892-29892 System.err              staging.xxxx.app                 W  	at kotlinx.coroutines.flow.internal.ChannelFlowOperator.collectTo$suspendImpl(ChannelFlow.kt:157)
    2022-12-22 17:13:12.908 29892-29892 System.err              staging.xxxx.app                 W  	at kotlinx.coroutines.flow.internal.ChannelFlowOperator.collectTo(Unknown Source:0)
    2022-12-22 17:13:12.908 29892-29892 System.err              staging.xxxx.app                 W  	at kotlinx.coroutines.flow.internal.ChannelFlow$collectToFun$1.invokeSuspend(ChannelFlow.kt:60)
    2022-12-22 17:13:12.908 29892-29892 System.err              staging.xxxx.app                 W  	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    2022-12-22 17:13:12.908 29892-29892 System.err              staging.xxxx.app                 W  	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
    2022-12-22 17:13:12.908 29892-29892 System.err              staging.xxxx.app                 W  	at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
    2022-12-22 17:13:12.908 29892-29892 System.err              staging.xxxx.app                 W  	at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
    2022-12-22 17:13:12.908 29892-29892 System.err              staging.xxxx.app                 W  	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
    2022-12-22 17:13:12.908 29892-29892 System.err              staging.xxxx.app                 W  	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
    2022-12-22 17:13:12.908 29892-29892 System.err              staging.xxxx.app                 W  	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
    2022-12-22 17:13:12.908 29892-29892 System.err              staging.xxxx.app                 W  	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
    2022-12-22 17:13:12.916 29892
    
    :car: Runtime :bug: Type: Bug 
    opened by ramanandsingh85 2
Releases(v3.7.3)
  • v3.7.3(Dec 20, 2022)

    This release contains a handful of bug fixes and improvements, and also discontinues the legacy JS artifacts.

    Many thanks to @StefanChmielewski and @chao2zhang for contributing to the project! 🧡

    ⚙️ Removed JS legacy artifacts (#4591)

    Historically, Kotlin Multiplatform has had 2 formats of JS artifacts: Legacy and IR, and Apollo Kotlin has been publishing both. However, the Legacy format is about to be deprecated with Kotlin 1.8 and moreover we've seen issues when using the Legacy artifact in the browser. That is why starting with this release, only the IR artifacts will be published. Please reach out if this causes any issue in your project.

    👷‍ All changes

    • Add GraphQLWsProtocol.Factory.webSocketPayloadComposer (#4589)
    • Escape "Companion" in enum value names (#4558)
    • Un-break Gradle configuration cache in multi module cases (#4564)
    • Move computing the alwaysGenerateTypesMatching to execution time (#4578)
    • Log deprecation warning instead of printing (#4561)
    • Escape spaces when url encoding, for Apple (#4567)
    • Fix providing linker flags to the Kotlin compiler with KGP 1.8 (#4573)
    • Use service {} in all messages/docs (#4572)
    • Print all duplicate types at once (#4571)
    • Fix JavaPoet formatting (#4584)
    • Don't publish legacy js artifacts (#4591)
    Source code(tar.gz)
    Source code(zip)
  • v3.7.2(Dec 5, 2022)

    This patch release brings a few fixes.

    Many thanks to @davidshepherd7, @chao2zhang, @agrosner, @MyDogTom, @doucheng, @sam43 and @vincentjames501, for helping improve the library! 🙏

    🔎‍ Explicit service declaration

    Apollo Kotlin can be configured to work with multiple services and have the package name, schema files location, and other options specified for each of them. When using a single service however it is possible to omit the service block and set the options directly in the apollo block - in that case, a default service named service is automatically defined.

    While this saves a few lines, it relies on Gradle afterEvaluate {} block that makes the execution of the plugin less predictable and more subject to race conditions with other plugins (see here for an example).

    What's more, as we move more logic to build time, the name of the service is going to be used more and more in generated code. Since explicit is better than implicit, mandating that service name sounds a good thing to do and a warning is now printed if you do not define your service name.

    To remove the warning, embed the options into a service block:

    apollo {
    + service("service") {
        packageName.set("com.example")
        // ...
    + }
    }
    

    👷‍ All changes

    • Improve "duplicate type" message by using the full path of the module (#4527)
    • Fix using apollo2 and apollo3 Gradle plugins at the same time (#4528)
    • Add a warning when using the default service (#4532)
    • Fix Java codegen in synthetic fields when using optionals (#4533)
    • Make canBeBatched and httpHeaders orthogonal (#4534)
    • Fix item wrongly removed from http cache when error in subscriptions (#4537)
    • Do not throw on graphql-ws errors and instead return the errors in ApolloResponse (#4540)
    • graphql-ws: send pong while waiting for connection_ack (#4555)
    Source code(tar.gz)
    Source code(zip)
  • v3.7.1(Nov 18, 2022)

    A patch release with a few fixes.

    👷‍ All changes

    • 👷Data Builders: make DefaultFakeResolver open and stateless (#4468)
    • Kotlin 1.7.21 (#4511)
    • Introduce HttpFetchPolicyContext (#4509)
    • Fix usedCoordinates on interfaces (#4506)

    Many thanks to @Holoceo, @juliagarrigos, @davidshepherd7 and @eduardb for the feedbacks 💙

    Source code(tar.gz)
    Source code(zip)
  • v2.5.14(Nov 18, 2022)

    A patch release to fix an issue where the ApolloCall could end up in a bad state. Many thanks to @WilliamsDHI for diving into this 💙!

    👷‍ All changes

    • update terminate and responseCallback methods to return Optional.absent() in IDLE/TERMINATED state (#4383)
    Source code(tar.gz)
    Source code(zip)
  • v3.7.0(Nov 8, 2022)

    This version adds multiple new low level features. These new features expose a lot of API surface, and they will probably stay experimental until 4.0. Feedback is always very welcome.

    ✨️ [new & experimental] compiler hooks API (#4474, #4026)

    Compiler hooks allow you to tweak the generated models by exposing the underlying JavaPoet/KotlinPoet structures. You can use it for an example to:

    • Add a 'null' default value to model arguments (source)
    • Introduce a common interface for all models that implement __typename (source)
    • Add a prefix to generated models (source)
    • Any other thing you can think of

    To do so, make sure to use the "external" version of the plugin:

    plugins {
      // Note: using the external plugin here to be able to reference KotlinPoet classes
      id("com.apollographql.apollo3.external")
    }
    

    And then register your hook to the plugin:

    apollo {
      service("defaultnullvalues") {
        packageName.set("hooks.defaultnullvalues")
        compilerKotlinHooks.set(listOf(DefaultNullValuesHooks()))
      }
    }
    

    ✨️ [new & experimental] operationBasedWithInterfaces codegen (#4370)

    By default, Apollo Kotlin models fragments with synthetic nullable fields. If you have a lot of fragments, checking these fields requires using if statements. For an example, with a query like so:

    {
      animal {
        species
        ... on WarmBlooded {
          temperature
        }
        ... on Pet {
          name
        }
        ... on Cat {
          mustaches
        }
      }
    }
    

    you can access data like so:

    if (animal.onWarmBlooded != null) {
      // Cannot smart cast because of https://youtrack.jetbrains.com/issue/KT-8819/
      println(animal.onWarmBlooded!!.temperature)
    }
    if (animal.onPet != null) {
      println(animal.onPet!!.name) 
    }
    if (animal.onCat != null) {
      println(animal.onCat!!.mustaches)
    }
    

    Some of the combinations could be impossible. Maybe all the pets in your schema are warm blooded. Or maybe only cat is a warm blooded. To model this better and work around KT-8819, @chalermpong implemented a new codegen that adds a base sealed interface. Different implementations contain the same synthetic fragment fields as in the default codegen except that their nullability will be updated depending the branch:

    when (animal) {
      is WarmBloodedPetAnimal -> {
        println(animal.onWarmBlooded!!.temperature)
        println(animal.onPet!!.name)
      }
      is PetAnimal -> {
        // Some pet that is not warm blooded, e.g. a Turtle maybe?
        println(animal.onPet!!.name)
      }
      is OtherAnimal -> {
        println(animal.species)
      }
      // Note how there is no branch for Cat because it's a WarmBloodedPetAnimal
      // Also no branch for WarmBlooded animal because all pets in this (fictional) sample schema are WarmBlooded. This could be different in another schema
    }
    

    To try it out, add this to your Gradle scripts:

    apollo {
      codegenModels.set("experimental_operationBasedWithInterfaces") 
    }
    

    Many many thanks to @chalermpong for diving into this 💙

    ✨️ [new & experimental] usedCoordinates auto detection (#4494)

    By default, Apollo Kotlin only generates the types that are used in your queries. This is important because some schemas are really big and generating all the types would waste a lot of CPU cycles. In multi-modules scenarios, the codegen only knows about types that are used locally in that module. If two sibling modules use the same type and that type is not used upstream, that could lead to errors like this:

    duplicate Type '$Foo' generated in modules: feature1, feature2
    Use 'alwaysGenerateTypesMatching' in a parent module to generate the type only once
    

    This version introduces new options to detect the used types automatically. It does so by doing a first pass at the GraphQL queries to determine the used type. Upstream modules can use the results of that computation without creating a circular dependency. To set up auto detection of used coordinates, configure your schema module to get the used coordinates from the feature module using the apolloUsedCoordinates configuration:

    // schema/build.gradle.kts
    dependencies {
      implementation("com.apollographql.apollo3:apollo-runtime")
      // Get the used coordinates from your feature module
      apolloUsedCoordinates(project(":feature"))
      // If you have several, add several dependencies
      apolloUsedCoordinates(project(":feature-2"))
    }
    apollo {
      service("my-api") {
        packageName.set("com.example.schema")
        generateApolloMetadata.set(true)
      }
    }
    

    And in each of your feature module, configure the apolloSchema dependency:

    // feature/build.gradle.kts
    dependencies {
      implementation("com.apollographql.apollo3:apollo-runtime")
      // Depend on the codegen from the schema
      apolloMetadata(project(":schema"))
      // But also from the schema so as not to create a circular dependency
      apolloSchema(project(":schema"))
    }
    apollo {
      // The service names must match
      service("my-api") {
        packageName.set("com.example.feature")
      }
    }
    

    👷‍ All changes

    • Add usedCoordinates configuration and use it to automatically compute the used coordinates (#4494)
    • Compiler hooks (#4474)
    • 🐘 Use registerJavaGeneratingTask, fixes lint trying to scan generated sources (#4486)
    • Rename generateModelBuilder to generateModelBuilders and add test (#4476)
    • Data builders: only generate used fields (#4472)
    • Only generate used types when generateSchema is true (#4471)
    • Suppress deprecation warnings, and opt-in in generated code (#4470)
    • Multi-module: fail if inconsistent generateDataBuilders parameters (#4462)
    • Add a decapitalizeFields option (#4454)
    • Pass protocols to WebSocket constructor in JSWebSocketEngine (#4445)
    • SQLNormalized cache: implement selectAll, fixes calling dump() (#4437)
    • Java codegen: Nullability annotations on generics (#4419)
    • Java codegen: nullability annotations (#4415)
    • OperationBasedWithInterfaces (#4370)
    • Connect test sourceSet only when testBuilders are enabled (#4412)
    • Java codegen: add support for Optional or nullable fields (#4411)
    • Add generatePrimitiveTypes option to Java codegen (#4407)
    • Add classesForEnumsMatching codegen option to generate enums as Java enums (#4404)
    • Fix data builders + multi module (#4402)
    • Relocate the plugin without obfuscating it (#4376)
    Source code(tar.gz)
    Source code(zip)
  • v3.6.2(Oct 5, 2022)

    A patch version to fix compatibility with Kotlin 1.7.20 and another fix when calling ApolloStore.dump() with the SQL normalized cache.

    👷‍ All changes

    • Add support for Kotlin Gradle Plugin 1.7.20 (#4439)
    • Fix SQLNormalizedCache.dump() (#4437)
    Source code(tar.gz)
    Source code(zip)
  • v3.6.1(Oct 3, 2022)

    A patch version to fix an issue with data builder and multi modules. Many thanks to @agrosner and @eduardb for catching this.

    👷‍ All changes

    • Fix data builders in multi-modules scenarios (#4402)
    Source code(tar.gz)
    Source code(zip)
  • v3.6.0(Sep 9, 2022)

    This version brings initial support for @defer as well as data builders.

    💙️ External contributors

    Many thanks to @engdorm, @Goooler, @pt2121 and @StylianosGakis for their contributions!

    ✨️ [new] @defer support

    @defer support is experimental in the Kotlin Client and currently a Stage 2 GraphQL specification draft to allow incremental delivery of response payloads.

    @defer allows you to specify a fragment as deferrable, meaning it can be omitted in the initial response and delivered as a subsequent payload. This improves latency for all fields that are not in that fragment. You can read more about @defer in the RFC and contribute/ask question in the @defer working group.

    Apollo Kotlin supports @defer by default and will deliver the successive payloads as Flow items. Given the below query:

    query GetComputer {
      computer {
        __typename
        id
        ...ComputerFields @defer
      }
    }
    
    fragment ComputerFields on Computer {
      cpu
      year
      screen {
        resolution
      }
    }
    

    And the following server payloads:

    payload 1:

    {
      "data": {
        "computer": {
          "__typename": "Computer",
          "id": "Computer1"
        }
      },
      "hasNext": true
    }
    

    payload 2:

    {
      "incremental": [
        {
          "data": {
            "cpu": "386",
            "year": 1993,
            "screen": {
              "resolution": "640x480"
            }
          },
          "path": [
            "computer",
          ]
        }
      ],
      "hasNext": true
    }
    

    You can listen to payloads by using toFlow():

    apolloClient.query(query).toFlow().collectIndexed { index, response ->
      // This will be called twice
    
      if (index == 0) {
        // First time without the fragment
        assertNull(response.data?.computer?.computerFields)
      } else if (index == 1) {
        // Second time with the fragment
        assertNotNull(response.data?.computer?.computerFields)
      }
    }
    

    You can read more about it in the documentation.

    As always, feedback is very welcome. Let us know what you think of the feature by either opening an issue on our GitHub repo , joining the community or stopping by our channel in the KotlinLang Slack(get your invite here).

    ✨️ [new] Data Builders (#4321)

    Apollo Kotlin 3.0 introduced test builders. While they are working, they have several limitations. The main one was that being response based, they could generate a lot of code. Also, they required passing custom scalars using their Json encoding, which is cumbersome.

    The data builders are a simpler version of the test builders that generate builders based on schema types. This means most of the generated code is shared between all your implementations except for a top level Data {} function in each of your operation:

    // Replace
    val data = GetHeroQuery.Data {
      hero = humanHero {
        name = "Luke"
      }
    } 
    
    // With
    val data = GetHeroQuery.Data {
      hero = buildHuman {
        name = "Luke"
      }
    } 
    

    ✨️ [new] Kotlin 1.7 (#4314)

    Starting with this release, Apollo Kotlin is built with Kotlin 1.7.10. This doesn't impact Android and JVM projects (the minimum supported version of Kotlin continues to be 1.5) but if you are on a project using Native, you will need to update the Kotlin version to 1.7.0+.

    👷‍ All changes

    • fix registering Java scalars. Many thanks @parker for catching this. (#4375)
    • Data builders (#4359, #4338, #4331, #4330, #4328, #4323, #4321)
    • Add a flag to disable fieldsCanMerge validation on disjoint types (#4342)
    • Re-introduce @defer and use new payload format (#4351)
    • Multiplatform: add enableCompatibilityMetadataVariant flag (#4329)
    • Remove an unnecessary file.source().buffer() (#4326)
    • Always use String for defaultValue in introspection Json (#4315)
    • Update Kotlin dependency to 1.7.10 (#4314)
    • Remove schema and AST from the IR (#4303)
    Source code(tar.gz)
    Source code(zip)
  • v2.5.13(Sep 7, 2022)

    A 2.x maintainance release with a couple of bugfixes. Many thanks to @eduardb for diving into #2818 💙

    What's Changed

    • Fix converting introspection to SDL by @martinbonnin in https://github.com/apollographql/apollo-kotlin/pull/4316
    • Fix writing fragments overwrites cache entries (#2818) by @eduardb in https://github.com/apollographql/apollo-kotlin/pull/4358

    Full Changelog: https://github.com/apollographql/apollo-kotlin/compare/v2.5.12...v2.5.13

    Source code(tar.gz)
    Source code(zip)
  • v3.5.0(Aug 1, 2022)

    With this release, Apollo Kotlin now uses Kotlin Native's new memory model. It also contains a number of other improvements and bug fixes.

    💙️ External contributors

    Many thanks to @glureau for carefully adding new watch targets ⌚💙

    ✨️ [new] Kotlin Native: new memory manager (#4287)

    Apollo Kotlin is now requiring applications to use the new memory manager, a.k.a. new memory model. Thanks to this change, the restriction that operations had to be executed from the main thread on Apple targets is now removed. You can also use kotlinx.coroutines.test.runTest. Last but not least, benchmarks seem to indicate that performance is better under the new memory manager!

    ✨️ [new] @targetName directive (#4243)

    This directive was introduced in v3.3.1 to allow overriding the name of enum values in the generated code. It has now been extended to allow configuring the generated name of Interfaces, Enums, Unions, Scalars and Input objects. This can be used to make the generated code nicer to use, or to avoid name clashes with Kotlin types (e.g. Long) in Kotlin Native.

    ✨️ [new] Automatic resolution of Apollo artifacts versions from the plugin version (#4279)

    From now on, you no longer need to specify explicitly the versions of Apollo dependencies: if omitted, the same version as the Apollo Gradle plugin will be used. This should facilitate upgrades and avoid potential mistakes:

    plugins {
      plugins {
        id("org.jetbrains.kotlin.jvm").version("1.7.10")
        id("com.apollographql.apollo3").version("3.5.0")
      }
    
      dependencies {
        // Replace this
        // implementation("com.apollographql.apollo3:apollo-runtime:3.5.0")
        
        // with
        implementation("com.apollographql.apollo3:apollo-runtime")
      }
    }
    
    

    🚧 [deprecated] runTest (#4292)

    With the new memory model, Apollo's specific runTest method from apollo-testing-support is no longer useful and has been deprecated. If you were using it, you should now be able to use Kotlin's runTest instead, or simply runBlocking.

    🚧 [breaking] Automatic detection of type enum values.

    If you have an enum with a type value, this value used to name clash with the generated type property. This version now detects this case automatically and escapes type to type_. If you had previously used @targetName to workaround this issue, you can now remove it to avoid it being escaped twice:

    # Remove this
    extend enum SomeEnum {
      type @targetName(name: "type_")
    }
    

    👷‍ All changes

    • Support watchosArm32 (#4260)
    • Support @targetName on Interfaces, Enums, Unions, Scalars and Input objects (#4243)
    • 🐘 support lazy APIs for newer AGP versions (#4264)
    • Pagination: add connectionFields argument to @typePolicy (#4265)
    • 🐘 Get the dependencies version from the plugin automagically (#4279)
    • Automatically escape type in enum values (#4295)
    • Fix inferred variables in both nullable and non-nullable locations (#4306)
    • Native: assume New Memory Manager (#4287)
    • Use internal runTest in all tests (#4292)
    Source code(tar.gz)
    Source code(zip)
  • v3.4.0(Jul 11, 2022)

    Version 3.4.0

    2022-07-11

    This release contains a few important bug fixes (#4214, #4224, #4247, #4256) and makes it possible to compile with Gradle 7.4 and apollo-gradle-plugin (#4218).

    It also introduces incubating cache artifacts.

    💙️ External contributors

    Many thanks to @ArjanSM, @zebehringer, @mm-kk-experiments, @mune0903, @stengvac, @elenigen, @shamsidinb and @StylianosGakis for the awesome contributions 😃!

    ✨️ [new] incubating cache artifacts.

    This version introduces the below artifacts:

    • apollo-normalized-cache-incubating
    • apollo-normalized-cache-api-incubating
    • apollo-normalized-cache-sqlite-incubating

    These artifacts introduce new APIs to work with cache expiration and pagination (as well as other cache improvements in the future).

    These artifacts have no backward compatibility guarantees and most likely have worse performance than the non-incubating artifacts. Documentation will be added once the API stabilize. In the short term, the best place to look for examples are the integration tests:

    Note: The experimental withDates: Boolean argument was introduced in 3.3.1 in the regular artifacts and is removed as part of this release. Use the incubating artifacts to use it.

    👷‍ All changes

    • add TrimmableNormalizedCacheFactory (#4239)
    • 🚧 remove withDates (#4257)
    • 🗄️ Chunk parameters in large responses (#4256)
    • Fix for improper handling of JsonNumber in BufferedSinkJsonWriter (#4247)
    • Incubating modules for the next gen cache (#4241)
    • Pagination: fixes in FieldRecordMerger and MemoryCache (#4237)
    • make it possible to reuse a File Upload (#4228)
    • Persist Record arguments/metadata with the SQL Json backend (#4211)
    • requestedDispatcher -> dispatcher (#4220)
    • Fix test errors were emitted outside the Flow (#4224)
    • Make it possible to compile with Kotlin 1.5 and apollo-gradle-plugin (#4218)
    • 🏖️ Relax MapJsonReader endObject, fixes reading inline + named fragments with compat models (#4214)
    • Introduce RecordMerger (#4197)
    • Add @typePolicy(embeddedFields: String! = "") (#4196)
    Source code(tar.gz)
    Source code(zip)
  • v3.3.2(Jun 17, 2022)

    This is a hot fix release that fixes a crash that could happen in the codegen when using responseBased codegen in a multimodule setup. It also includes a fix for incorrect generated code when using certain reserved names in enum values.

    👷‍ All changes

    • Update to KotlinPoet 1.12.0, fixes generating enum values whose name clashes with other symbols (#4034)
    • Update to Ktor 2 (#4190)
    • Fix NPE in checkCapitalizedFields (#4201)
    Source code(tar.gz)
    Source code(zip)
  • v2.5.12(Jun 14, 2022)

    Version 2.5.12 is a maintenance release with a fix to restore downloading schemas as SDL, and a fix for Kotlin 1.7 compatibility.

    💜 Many thanks to @eg-ndobrijevic and @remcomokveld for raising these issues! 💜

    👷 All Changes

    • [2.x] restore SDL download (#4046)
    • Fix Kotlin 1.7 compatibility (#4187)
    Source code(tar.gz)
    Source code(zip)
  • v3.3.1(Jun 13, 2022)

    This release introduces @typePolicy on interface/enums, improvements on subscription error handling, and on Test Builders. It also contains a number of other improvements and bug fixes!

    ✨️ [new] @typePolicy on interfaces and unions (#4131)

    The @typePolicy directive can now be declared on interfaces and unions. Thank you @bubba for the contribution!

    🔌 WebSockets / Subscriptions error handling (#4147)

    An issue where websocketReopenWhen was not called in some cases was fixed. Also, this release introduces SubscriptionOperationException. A SubscriptionOperationException will be thrown instead of the more generic ApolloNetworkError if a subscription fails due to a specific operation error.

    📐 Test Builders improvements and fixes

    • A DslMarker was added to improve usage with nested builders (#4089)
    • When calling a builder, but not assigning it to a field, an error is now thrown, preventing mistakes (#4122)
    • The error message displayed when __typename is missing was made clearer (#4146)
    • Fix: use rawValue instead of name for enums (#4121)

    ✨️ [new] ApolloClient implements Closable (#4142)

    ApolloClient now implements okio.Closable so you can use use with it. Thanks @yogurtearl for this contribution!

    ✨️ [new] experimental @targetName directive on enum values (#4144)

    If an enum value name is clashing with a reserved name (e.g. type) you can now use this directive to instruct the codeGen to use the specified name for the value instead. This directive is experimental for now.

    ✨️ [new] experimental support for renaming directives (#4174)

    As we add more client directives, the risk of nameclash with existing schema directives increases. If this happens, you can now import Apollo client directives using @link:

    # extra.graphqls
    extend schema @link(url: "https://specs.apollo.dev/kotlin_labs/v0.1") 
    

    This adds a @kotlin_labs__ prefix to all Apollo client directives:

    {
      hero {
        name @kotlin_labs__nonnull
      }
    }
    

    🤖 SqlNormalizedCacheFactory initialization on Android (#4104)

    It is no longer necessary to pass a Context when initializing the SqlNormalizedCacheFactory on Android. A Context is automatically provided, via App Startup.

    // Before
    val sqlNormalizedCacheFactory = SqlNormalizedCacheFactory(context, "apollo.db")
    // After
    val sqlNormalizedCacheFactory = SqlNormalizedCacheFactory("apollo.db")
    

    📝 [new] Public API tracking

    This release starts tracking the public API of all modules, including MockServer. Even if the API remains experimental, we'll try to keep the number of breaking changes low in the future.

    👷‍ All changes

    • 🐘 publish apollo-gradle-plugin-external (#4078)
    • publish the R8 mapping file along the relocated jar (#4085)
    • Fix test directories not cleared (#4083)
    • Do not use 'header' as a enum value name as it breaks the Kotlin compiler (#4086)
    • 🧪 @experimental support (#4091)
    • @experimental -> @requiresOptIn (#4175)
    • Do not buffer entire body in Http Cache (#4076)
    • ⬇️ add SchemaDownloader.download() (#4088)
    • add DslMarker for test builders (#4089)
    • MockServer: make MockResponse.body a Flow (#4096)
    • Issue-3909: add ApolloResponse cache headers (#4102)
    • Use rawValue instead of name for enums in test builders (#4121)
    • 💧 first drop for a SQLite backend that stores when each field was last updated (#4104)
    • Add Operation.Data.toJsonString() convenience function for the jvm (#4124)
    • Check for unassigned fields in Test Builders (#4122)
    • Add non-breaking spaces after 'return' (#4127)
    • 🧶 Use a getter instead of a const val OPERATION_QUERY (#4130)
    • Uploads should be read only once even when logging (#4125)
    • Keep the 'interfaces' field on the JSON introspection (#4129)
    • Allow @typePolicy directive on interfaces and unions (#4131)
    • typePolicy on interface: exclude empty keyfields (#4140)
    • Sort the type names in the list so the code gen is deterministic. (#4138)
    • Use okio.Closable.close instead of dispose on ApolloClient (#4142)
    • Parse the interface's interface field in introspection (#4143)
    • TestBuilders: improve error message when __typename is missing (#4146)
    • Do not bypass websocketReopenWhen {} (#4147)
    • SDLWriter: join implemented interfaces with & instead of space (#4151)
    • Escape "type" in enums and sealed classes (#4144)
    • 🧰 introduce apollo-tooling and apollo-cli (#4153)
    • Fix incorrect content-length in MockServer (#4162)
    • Allow capitalized field names if flattenModels is true (#4154)
    • 🏷️ Allow namespacing and renaming of directives (#4174)

    ❤️ External contributors

    Many thanks to @tajchert, @asimonigh, @hrach, @ArjanSM, @yshrsmz, @ephemient, @bubba, @eboudrant and @yogurtearl for contributing to this release! 🙏

    Source code(tar.gz)
    Source code(zip)
  • v3.3.0(May 4, 2022)

    This is the first release with HMPP support. If you're using multiplatform, updating to Kotlin 1.6.21 is strongly encouraged.

    This release also brings WebSocket related improvements and other fixes!

    ✨️ [new] Hierarchical MultiPlatform Project (HMPP) (#4033)

    When using Apollo Kotlin on a multiplatform project, this release is compatible with the hierarchical project structure, which makes it easier to share common code among several targets. Using HMPP in your project also fixes some issues when compiling Kotlin metadata. See https://github.com/apollographql/apollo-kotlin/issues/4019 and https://youtrack.jetbrains.com/issue/KT-51970/ for more details.

    ✋ Note: If you're using multiplatform, we strongly encourage updating to Kotlin 1.6.21. If that is not an option, you might have issues resolving dependencies. More infos in this issue.

    ✨️ [new] WebSocketNetworkTransport.closeConnection (#4049)

    This new method can be used in conjunction with reopenWhen to force a reconnection to the server. This could be useful for instance when needing to pass new auth tokens in the headers. If you were using subscriptionManager.reconnect() in 2.x, closeConnection is a simple way to achieve the same behaviour.

    ✨️ [new] GraphQLWsProtocol.connectionPayload is now a lambda (#4043)

    With GraphQLWsProtocol, if you need to pass parameters to the connection payload, previously you would pass them as a static map to the builder. With this change you can now pass a lambda providing them as needed. This facilitates passing fresh auth tokens when connecting.

    ✨️ [new] Add insecure option to download schema (#4021)

    You can now use the --insecure flag when downloading a schema with downloadApolloSchema, to bypass the certificate check, which can be useful if a server is configured with a self-signed certificate for instance.

    👷‍ All changes

    • Add WebSocketNetworkTransport.closeConnection (#4049)
    • Made connectionPayload as suspend function in GraphQLWsProtocol (#4043)
    • ⚡ Ignore unknown websocket messages (#4066)
    • Kotlin 1.6.21 & HMPP (#4033)
    • Provide a Content-Length when using Upload (#4056)
    • ☁️ add HttpRequest.newBuilder(url, method) (#4038)
    • Escape enum constants (#4035)
    • Fix the Moshi adapter used for OperationOutput. Moshi cannot get the type parameters from the typealias automagically (#4022)
    • Add insecure option to download schema (#4021)
    • Try to reduce allocations in MapJsonReader (#3935)
    • 🔒 Deprecate BearerTokenInterceptor and provide tests and docs instead (#4068)

    ❤️ External contributors

    Many thanks to @CureleaAndrei and @kdk96 for contributing to this release! 🙏

    ⚙️ Deprecations

    • BearerTokenInterceptor was provided as an example but is too simple for most use cases, and has therefore been deprecated in this release. This page provides more details about authentication.
    • The previous ways of passing parameters to the connection payload with GraphQLWsProtocol has been deprecated (see above).
    Source code(tar.gz)
    Source code(zip)
  • v3.2.2(Apr 11, 2022)

    Version 3.2.2

    Many thanks to @benedict-lim, @olivierg13, @konomae and @sproctor for their contributions 💙

    3.2.2 is a maintenance release to fix the addJvmOverloads option added in 3.2.0 as well as other fixes. If you're using APQs, the mutations are now always send using POST. See #4006 for details and a way to override the behaviour if you need to.

    👷‍ All changes

    • Use a constant for JvmOverloads to avoid a crash due to relocation (#4008)
    • Always use POST for Mutations in APQs (Auto Persisted Queries) (#4011)
    • Add configurable headers to WebSocketNetworkTransport (#3995)
    • Handle SqlNormalizedCache merge APIs Exceptions with ApolloExceptionHandler (#4002)
    • Add adapter for java.time.OffsetDateTime (#4007)
    • ⏰ Add tests for date adapters (#3999)
    • Fix wrong LocalDate and LocalDateTime formats in JavaTimeAdapters (#3997)
    Source code(tar.gz)
    Source code(zip)
  • v3.2.1(Apr 5, 2022)

    This release introduces a few improvements and bug fixes.

    ✨️ [new] ApolloCall<D>.emitCacheMisses(Boolean) (#3980)

    When observing the cache with watch, the behavior was to not emit cache misses at all, which may not desirable in certain cases. With this new option, you can now choose to emit them: in that case responses will be emitted with a null data.

    This can be used like so:

    apolloClient.query(query)
      .fetchPolicy(FetchPolicy.CacheOnly)
      .emitCacheMisses(true)
      .watch()
      .collect { response ->
        // response.data will be null in case of cache misses
      }
    

    This is also closer to the behavior that was in place in v2. Many thanks to @mateuszkwiecinski for the insights and raising the issue!

    ⚙️ [breaking] Allow configuration of frame types used in SubscriptionWsProtocol and default to Text (#3992)

    When using subscriptions over WebSockets with SubscriptionWsProtocol (the default), the frames were sent in the binary format. It was reported that this was not compatible with certain servers (DGS, graphql-java-kickstart) that are expecting text frames. This is now fixed and the default is to send text frames.

    ⚠️ This may be a breaking change if your server expects binary frames only! If that is the case, you can use the new frameType option to configure the frame type to be sent:

    client = ApolloClient.Builder()
      .webSocketServerUrl("wss://...")
      .wsProtocol(GraphQLWsProtocol.Factory(frameType = WsFrameType.Binary))
      .build()
    

    Many thanks to @Krillsson and @aviewfromspace1 for the insights and raising the issue!

    👷‍ All changes

    • Allow configuration of frame types used in SubscriptionWsProtocol and default to Text (#3992)
    • add ApolloRequest.newBuilder(operation: Operation<E>) (#3988)
    • Add exception handlers to ApolloCacheInterceptor and SqlNormalizedCache (#3989)
    • 📠 Fix some @DeprecatedSince annotations (#3983)
    • 👓 add ApolloCall.emitCacheMisses(Boolean) (#3980)
    • ⚙️ Fix fragments on the root query type in operationBased codegen (#3973)

    ❤️ External contributors

    Many thanks to @AdamMTGreenberg and @Krillsson for the contributions! 🙏

    Source code(tar.gz)
    Source code(zip)
  • v3.2.0(Mar 29, 2022)

    💙 Thanks to @undermark5, @demoritas, @rkoron007, @akshay253101, @StylianosGakis, @Goooler, @jeffreydecker, @theBradfo, @anderssandven and @olivierg13 for contributing to this release.

    This version adds JS WebSocket support, more options to deal with __typename amongst other features and bugfixes.

    ✨️ [new] JS WebSocket support (#3913)

    Version 3.2.0 now has WebSocket support for Javascript targets courtesy of @undermark5! This is a huge milestone and means the JS target is now even closer to its JVM and iOS counterparts.

    | | jvm | Apple | js | linuxX64 | --- | :---: |:-----:|:----:| :---: | | apollo-api (models)|✅| ✅ | ✅ |✅| | apollo-runtime (network, query batching, apq, ...) |✅| ✅ | ✅ |🚫| | apollo-normalized-cache |✅| ✅ | ✅ |🚫| | apollo-adapters |✅| ✅ | ✅ |🚫| | apollo-normalized-cache-sqlite |✅| ✅ | 🚫 |🚫| | apollo-http-cache |✅| 🚫 | 🚫 |🚫|

    The implementation is based on the ws library on Node and the WebSocket API on the browser and inspired by Ktor.

    ✨️ [new] Fine grained __typename control (#3939)

    This version generates non-nullable fragments when it knows the fragment is always present:

    {
      cat {
        # Because Animal is a supertype of Cat this condition will always be true
        ... on Animal {
          species
        }
      }
    }
    

    In addition, it introduces a addTypename Gradle option to have better control over when to add the __typename field:

    /**
     * When to add __typename. One of "always", "ifFragments", "ifAbstract" or "ifPolymorphic"
     *
     * - "always": Add '__typename' for every compound field
     *
     * - "ifFragments": Add '__typename' for every selection set that contains fragments (inline or named)
     * This is adding a lot more '__typename' than the other solutions and will be certainly removed in
     * a future version. If you require '__typename' explicitly, you can add it to your queries.
     * This causes cache misses when introducing fragments where no fragment was present before and will be certainly removed in
     * a future version.
     *
     * - "ifAbstract": Add '__typename' for abstract fields, i.e. fields that are of union or interface type
     * Note: It also adds '__typename' on fragment definitions that satisfy the same property because fragments
     * could be read from the cache and we don't have a containing field in that case.
     *
     * - "ifPolymorphic": Add '__typename' for polymorphic fields, i.e. fields that contains a subfragment
     * (inline or named) whose type condition isn't a super type of the field type.
     * If a field is monomorphic, no '__typename' will be added.
     * This adds the bare minimum amount of __typename but the logic is substantially more complex and
     * it could cause cache misses when using fragments on monomorphic fields because __typename can be
     * required in some cases.
     *
     * Note: It also adds '__typename' on fragment definitions that satisfy the same property because fragments
     * could be read from the cache and we don't have a containing field in that case.
     *
     * Default value: "ifFragments"
     */
    

    You can read more in the corresponding Typename.md design document.

    ✨️ [new] Maven publishing for multi-module apollo metadata (#3904)

    The Apollo Gradle plugin now creates a new "apollo" publication if maven-publish is found. This means you can now publish the Apollo metadata to a maven repository:

    # In your producer project
    ./gradlew publishApolloPublicationTo[SomeRepository]
    

    Assuming your producer project is using com.example:project:version for maven coordinates, the Apollo metadata will be published at com.example:project-apollo:version:

    // In your consumer project
    dependencies {
      implementation("com.example:project:version")
      apolloMetadata("com.example:project-apollo:version")
    }
    

    Note: There are absolutely no forward/backward compatibility guarantees for Apollo metadata yet. The Apollo version used in the consumer must be the same as the one used in the producer.

    ✨️ [new] addJvmOverloads Gradle option (#3907)

    For better Java interop, you can now opt-in addJvmOverloads. addJvmOverloads will add the @JvmOverloads to your Kotlin operations:

    @JvmOverloads
    class GetHeroQuery(val id: String, val episode: Optional<Episode> = Optional.Absent) {
      // ...
    }
    

    Meaning you can now create a new query from Java without having to specify episode: new GetHeroQuery("1002")

    👷‍ All changes

    • 📖 Add note to tutorial about graphql-ws library to tutorial (#3961)
    • Use ApolloCompositeException for HTTP CachePolicies (#3967)
    • 🖋️ bump kotlin poet to 1.11.0 (#3970)
    • Add underlying exceptions as suppressed exceptions in ApolloCompositeException (#3957)
    • Add macosArm64 and macosX64 targets (#3954)
    • JS Websockets: handle remote close (#3952)
    • ⚙️ Introduce addTypename Gradle parameter (#3939)
    • Optimize CI a bit (#3942)
    • Add more field merging diagnostics (#3937)
    • ⚙️ Make adapters code work without relying on having a__typename IrProperty (#3930)
    • Add equals and hashCode implementations for models with no properties (#3928)
    • 🐘 Unbreak Gradle configuration cache (#3918)
    • WebSocket support for JS targets (#3913)
    • 🗄️ add apolloClient.httpCache (#3919)
    • ⚙️ Detect case insensitive filesystems (like MacOS default one) and rename classes when that happens (#3911)
    • Fix exceptions where not caught when reading the body of a batched query (#3910)
    • 🗄️ Fix writing fragments programmatically was using the wrong cache key (#3905)
    • 📦 Maven publishing for Apollo metadata (#3904)
    • Add addJvmOverloads Gradle option for better Java interop (#3907)
    • 🐘 Fix using refreshVersions (#3898)
    • add support for triple quotes escapes (#3895)
    • 👷 Test Builders: Fix enums in test resolver (#3894)
    • Validation: Detect missing arguments when there are no arguments at all (#3893)
    • Add support for receiving multiple bodies with multipart (#3889)
    • ✅ Validation: allow nullable variables in non-null locations if there is a default value (#3879)
    • ??️ HttpCache: do not cache mutations by default (#3873)
    • Chunked Transfer-Encoding support in MockServer (#3870)
    • Fix -1 body length in BatchingHttpInterceptor (#3874)
    • Fix issue in Java codegen where selectors returned ImmutableMapBuilder instances instead of Map (#3861)
    • Make watchers subscribe to the store earlier (#3853)
    Source code(tar.gz)
    Source code(zip)
  • v3.1.0(Feb 7, 2022)

    Version 3.1.0 introduces new APIs for testing, mapping scalars as well a redesigned cache pipeline. It also contains bugfixes around the @include directives, MemoryCache and GraphQL validation amongst other changes.

    ⚙️ [breaking] Fragment package name and useSchemaPackageNameForFragments (#3775)

    If you're using packageNameFromFilePath(), the package name of generated fragment classes has changed.

    Different generated types have different package names:

    • Generated types coming from operations are generated based on the operation path
    • Generated types coming from the schema (input objects, custom scalars and enums) are generated based on the schema path

    Previously, fragments were using the schema path which is inconsistent because fragments are not defined in the schema but are executable files, like operations.

    Version 3.1.0 now uses the same logic for fragments as for operations. To revert to the previous behaviour, you can use useSchemaPackageNameForFragments:

    apollo {
      useSchemaPackageNameForFragments.set(true)
    }
    

    This is also done automatically if you're using useVersion2Compat(). Moving forward, the plan is to remove useSchemaPackageNameForFragments in favor of setting a custom PackageNameGenerator. If you have use cases that require useSchemaPackageNameForFragments, please reach out.

    ✨ [New] QueueTestNetworkTransport (#3757)

    3.1.0 introduces QueueTestNetworkTransport to test at the GraphQL layer without needing to run an HTTP server.

    To use it, configure your ApolloClient:

    // This uses a QueueTestNetworkTransport that will play the queued responses
    val apolloClient = ApolloClient.Builder()
        .networkTransport(QueueTestNetworkTransport())
        .build()
    

    You can then use the enqueueTestResponse extension function to specify the GraphQL responses to return:

    val testQuery = GetHeroQuery("001")
    val testData = GetHeroQuery.Data {
      hero = droidHero {
        name = "R2D2"
      }
    }
    apolloClient.enqueueTestResponse(testQuery, testData)
    val actual = apolloClient.query(testQuery).execute().data!!
    assertEquals(testData.hero.name, actual.hero.name)
    

    ✨ [New] MockServerHandler (#3757)

    If you're testing at the HTTP layer, you can now define your own MockServerHandler to customize how the server is going to answer to requests:

    val customHandler = object : MockServerHandler {
      override fun handle(request: MockRequest): MockResponse {
        return if (/* Your custom logic here */) {
          MockResponse(
              body = """{"data": {"random": 42}}""",
              headers = mapOf("X-Test" to "true"),
          )
        } else {
          MockResponse(
              body = "Internal server error",
              statusCode = 500,
          )
        }
      }
    }
    val mockServer = MockServer(customHandler)
    

    ✨ [New] FetchPolicy.CacheAndNetwork (#3828)

    Previously, FetchPolicys were limited to policies that emitted at most one response. There was a executeCacheAndNetwork() method but it felt asymmetrical. This version introduces FetchPolicy.CacheAndNetwork that can emit up to two responses:

    apolloClient.query(query)
      // Check the cache and also use the network (1 or 2 values can be emitted)
      .fetchPolicy(FetchPolicy.CacheAndNetwork)
      // Execute the query and collect the responses
      .toFlow().collect { response ->
          // ...
      }
    

    ✨ [New] ApolloCall<D>.fetchPolicyInterceptor(interceptor: ApolloInterceptor) (#3743)

    If you need more customized ways to fetch data from the cache or more fine-grained error handling that does not come with the built-in FetchPolicy, you can now use fetchPolicyInterceptor:

    // An, interceptor that will only use the network after getting a successful response
    val refetchPolicyInterceptor = object : ApolloInterceptor {
      var hasSeenValidResponse: Boolean = false
      override fun <D : Operation.Data> intercept(request: ApolloRequest<D>, chain: ApolloInterceptorChain): Flow<ApolloResponse<D>> {
        return if (!hasSeenValidResponse) {
          CacheOnlyInterceptor.intercept(request, chain).onEach {
            if (it.data != null) {
              // We have valid data, we can now use the network
              hasSeenValidResponse = true
            }
          }
        } else {
          // If for some reason we have a cache miss, get fresh data from the network
          CacheFirstInterceptor.intercept(request, chain)
        }
      }
    }
    
    apolloClient.query(myQuery)
        .refetchPolicyInterceptor(cacheOnlyInterceptor)
        .watch()
        .collect {
          //
        }
    

    ✨ [New] Service.mapScalar Gradle API (#3779)

    You can now use mapScalar to specify your scalar mappings:

    apollo {
      // Replace 
      customScalarsMapping.set(mapOf(
          "Date" to "java.util.Date"
      ))
      
      // With
      mapScalar("Date", "java.util.Date")
    }
    

    mapScalar also works with built-in scalar types so you can map the ID type to a kotlin Long:

    apollo {
      // This requires registering an adapter at runtime with `addCustomScalarAdapter()` 
      mapScalar("ID", "kotlin.Long")
    }
    

    As an optimization, you can also provide the adapter at compile time. This will avoid a lookup at runtime everytime such a scalar is read:

    apollo {
      // No need to call `addCustomScalarAdapter()`, the generated code will use the provided adapter 
      mapScalar("ID", "kotlin.Long", "com.apollographql.apollo3.api.LongAdapter")
    }
    

    For convenience, a helper function is provided for common types:

    apollo {
      // The generated code will use `kotlin.Long` and the builtin LongAdapter 
      mapScalarToKotlinLong("ID")
    
      // The generated code will use `kotlin.String` and the builtin StringAdapter
      mapScalarToKotlinString("Date")
    
      // The generated code will use `com.apollographql.apollo3.api.Upload` and the builtin UploadAdapter
      mapScalarToUpload("Upload")
    }
    

    🚧 [Changed] convertApolloSchema and downloadApolloSchema now use paths relative to the root of the project (#3773, #3752)

    Apollo Kotlin adds two tasks to help to manage schemas: convertApolloSchema and downloadApolloSchema. These tasks are meant to be used from the commandline.

    Previously, paths were interpreted using the current working directory with File(path). Unfortunately, this is unreliable because Gradle might change the current working directory in some conditions (see Gradle#13927 or Gradle#6074 for an example).

    With 3.1.0 and onwards, paths, will be interpreted relative to the root project directory (project.rootProject.file(path)):

    # schema is now interpreted relative to the root project directory and
    # not the current working directory anymore. This example assumes there 
    # is a 'app' module that applies the apollo plugin
    ./gradlew downloadApolloSchema \
      --endpoint="https://your.domain/graphql/endpoint" \
      --schema="app/src/main/graphql/com/example/schema.graphqls"
    

    ❤️ External contributors

    Many thanks to @dhritzkiv, @mune0903, @StylianosGakis, @AchrafAmil and @jamesonwilliams for their awesome contributions! You rock 🎸 🤘 !

    👷 All changes

    • Fix error reporting when there is a "schema.graphqls" but it doesn't contain any type definition (#3844)
    • Make guessNumber read the next value only once, fixes parsing custom scalars without a custom adapter (#3839, #3836)
    • Clarify need to pass client's customScalarAdapters to store methods (#3838)
    • Fix null pointer exception in LruCache while trimming (#3833)
    • Add FetchPolicy.CacheAndNetwork (#3828)
    • Allow to specify error handling for watch() (#3817)
    • Scalar mapping and adapter configuration improvements (#3779)
    • Tunnel variables in CustomScalarAdapters (#3813)
    • Terminate threads correctly if no subscription has been executed (#3803)
    • fix validation of merged fields (#3799)
    • Make reconnectWhen suspend and pass attempt number (#3772)
    • Merge HTTP headers when batching (#3776)
    • MockServer improvements and TestNetworkTransport (#3757)
    • Fix calling ApolloClient.newBuilder() if the original ApolloClient used .okHttpClient (#3771)
    • Make convertApolloSchema and downloadApolloSchema use path from the root of the project (#3773, #3752)
    • fix fragment package name in multi-module scenarios (#3775)
    • Make the error printer robust to unknown source locations, fixes schemas with duplicate types (#3753)
    • Allow to customize the fetchPolicy with interceptors (#3743)
    Source code(tar.gz)
    Source code(zip)
  • v3.0.0(Dec 16, 2021)

    This is the first stable release for ~Apollo Android 3~ Apollo Kotlin 3 🎉!

    There is documentation, a migration guide and a blog post.

    In a nutshell, Apollo Kotlin 3 brings:

    • coroutine APIs for easier concurrency
    • multiplatform support makes it possible to run the same code on Android, JS, iOS, MacOS and linux
    • responseBased codegen is a new optional codegen that models fragments as interfaces
    • SQLite batching makes reading from the SQLite cache significantly faster
    • Test builders offer a simple APIs to build fake models for your tests
    • The @typePolicy and @fieldPolicy directives make it easier to define your cache ids at compile time
    • The @nonnull directive catches null values at parsing time, so you don't have to deal with them in your UI code

    Feel free to ask questions by either opening an issue on our GitHub repo, joining the community or stopping by our channel in the KotlinLang Slack(get your invite here).

    Changes compared to 3.0.0-rc03:

    • Fix rewinding the Json stream when lists are involved (#3727)
    • Kotlin 1.6.10 (#3723)
    • Disable key fields check if unnecessary and optimize its perf (#3720)
    • Added an easy way to log cache misses (#3724)
    • Add a Data.toJson that uses reflection to lookup the adapter (#3719)
    • Do not run the cache on the main thread (#3718)
    • Promote JsonWriter extensions to public API (#3715)
    • Make customScalarAdapters and subscriptionsNetworkTransport public (#3714)
    Source code(tar.gz)
    Source code(zip)
  • v3.0.0-rc03(Dec 13, 2021)

    Compared to the previous RC, this version adds a few new convenience API and fixes 3 annoying issues.

    💙 Many thanks to @mateuszkwiecinski, @schoeda and @fn-jt for all the feedback 💙

    ✨ New APIs

    • Make ApolloCall.operation public (#3698)
    • Add SubscriptionWsProtocolAdapter (#3697)
    • Add Operation.composeJsonRequest (#3697)

    🪲 Bug fixes

    • Allow repeated @fieldPolicy (#3686)
    • Fix incorrect merging of nested objects in JSON (#3672)
    • Fix duplicate query detection during validation (#3699)
    Source code(tar.gz)
    Source code(zip)
  • v3.0.0-rc02(Dec 10, 2021)

    💙 Many thanks to @michgauz, @joeldenke, @rohandhruva, @schoeda, @CoreFloDev and @sproctor for all the feedback 💙

    ⚙️ [breaking] Merge ApolloQueryCall, ApolloSubscriptionCall, ApolloMutationCall (#3676)

    In order to simplify the API and keep the symmetry with ApolloRequest<D> and ApolloResponse<D>, ApolloQueryCall<D, E>, ApolloSubscriptionCall<D, E>, ApolloMutationCall<D, E> are replaced with ApolloCall<D>. This change should be mostly transparent but it's technically a breaking change. If you are passing ApolloQueryCall<D, E> variables, it is safe to drop the second type parameter and use ApolloCall<D> instead.

    ✨ [New] Add WebSocketNetworkTransport.reconnectWhen {} (#3674)

    You now have the option to reconnect a WebSocket automatically when an error happens and re-subscribe automatically after the reconnection has happened. To do so, use the webSocketReconnectWhen parameter:

    val apolloClient = ApolloClient.Builder()
        .httpServerUrl("http://localhost:8080/graphql")
        .webSocketServerUrl("http://localhost:8080/subscriptions")
        .wsProtocol(
            SubscriptionWsProtocol.Factory(
                connectionPayload = {
                  mapOf("token" to upToDateToken)
                }
            )
        )
        .webSocketReconnectWhen {
          // this is called when an error happens on the WebSocket
          it is ApolloWebSocketClosedException && it.code == 1001
        }
        .build()
    

    Better Http Batching API (#3670)

    The HttpBatchingEngine has been moved to an HttpInterceptor. You can now configure Http batching with a specific method:

    apolloClient = ApolloClient.Builder()
        .serverUrl(mockServer.url())
        .httpBatching(batchIntervalMillis = 10)
        .build()
    

    All changes:

    • Add 2.x symbols (Rx2Apollo, prefetch(), customAttributes(), ApolloIdlingResource.create()) to help the transition (#3679)
    • Add canBeBatched var to ExecutionOptions (#3677)
    • Merge ApolloQueryCall, ApolloSubscriptionCall, ApolloMutationCall (#3676)
    • Add WebSocketNetworkTransport.reconnectWhen {} (#3674)
    • Move BatchingHttpEngine to a HttpInterceptor (#3670)
    • Add exposeErrorBody (#3661)
    • fix the name of the downloadServiceApolloSchemaFromRegistry task (#3669)
    • Fix DiskLruHttpCache concurrency (#3667)
    Source code(tar.gz)
    Source code(zip)
  • v3.0.0-rc01(Dec 7, 2021)

    This version is the release candidate for Apollo Android 3 🚀. Please try it and report any issues, we'll fix them urgently.

    There is documentation and a migration guide. More details are coming soon. In a nutshell, Apollo Android 3 brings, amongst other things:

    • coroutine APIs for easier concurrency
    • multiplatform support makes it possible to run the same code on Android, JS, iOS, MacOS and linux
    • responseBased codegen is a new optional codegen that models fragments as interfaces
    • SQLite batching makes reading from the SQLite cache significantly faster
    • Test builders offer a simple APIs to build fake models for your tests
    • The @typePolicy and @fieldPolicy directives make it easier to define your cache ids at compile time
    • The @nonnull directive catches null values at parsing time, so you don't have to deal with them in your UI code

    Compared to beta05, this version changes the default value of generateOptionalOperationVariables, is compatible with Gradle configuration cache and fixes a few other issues.

    ⚙️ API changes

    Optional operation variables (#3648) (breaking)

    The default value for the generateOptionalOperationVariables config is now true.

    What this means:

    • By default, operations with nullable variables will be generated with Optional parameters
    • You will need to wrap your parameters at the call site

    For instance:

    query GetTodos($first: Int, $offset: Int) {
      todos(first: $first, offset: $offset) {
        ...Todo
      }
    }
    
    // Before
    val query = GetTodosQuery(100, null)
    
    // After
    val query = GetTodosQuery(Optional.Present(100), Optional.Absent)
    
    
    • If you prefer, you can set generateOptionalOperationVariables to false to generate non-optional parameters globally
    • This can also be controlled on individual variables with the @optional directive
    • More information about this can be found here

    We think this change will make more sense to the majority of users (and is consistent with Apollo Android v2's behavior) even though it may be more verbose, which is why it is possible to change the behavior via the generateOptionalOperationVariables config.

    To keep the beta05 behavior, set generateOptionalOperationVariables to false in your Gradle configuration:

    apollo {
      generateOptionalOperationVariables.set(false)
    }
    

    ApolloClient.Builder improvements (#3647)

    You can now pass WebSocket related options to the ApolloClient.Builder directly (previously this would have been done via NetworkTransport):

    // Before
    val apolloClient = ApolloClient.Builder()
        // (...)
        .subscriptionNetworkTransport(WebSocketNetworkTransport(
            serverUrl = "https://example.com/graphql",
            idleTimeoutMillis = 1000L,
            wsProtocol = SubscriptionWsProtocol.Factory()
        ))
        .build()
    
    // After
    val apolloClient = ApolloClient.Builder()
        // (...)
        .wsProtocol(SubscriptionWsProtocol.Factory())
        .webSocketIdleTimeoutMillis(1000L)
        .build()
    

    Upgrade to OkHttp 4 (#3653) (breaking)

    This version upgrades OkHttp to 4.9.3 (from 3.12.11). This means Apollo Android now requires Android apiLevel 21+. As OkHttp 3 enters end of life at the end of the year and the vast majority of devices now support apiLevel 21, we felt this was a reasonable upgrade.

    🪲 Bug fixes

    • Fixed an issue where it was not possible to restart a websocket after a network error (#3646)
    • Fixed an issue where Android Java projects could not use the Apollo Gradle plugin (#3652)

    👷 All Changes

    • Update a few dependencies (#3653)
    • Fix Android Java projects (#3652)
    • Expose more configuration options on ApolloClient.Builder (#3647)
    • Fix restarting a websocket after a network error (#3646)
    • Change optional default value (#3648)
    • Fix configuration cache (#3645)
    Source code(tar.gz)
    Source code(zip)
  • v3.0.0-beta05(Dec 3, 2021)

    We intended this version to be the first release candidate but we found a few bugs justifying a new beta instead. Many thanks to @CoreFloDev, @olivierg13, @rohandhruva, @adavis and @sproctor for identifying the bugs and sending feedback, this helps a ton 🙏 💙 . Next one should be release candidate 🤞 🚀

    🪲 Bug fixes

    • Fix a crash when using Auto Persisted Queries on iOS (#3637)
    • Fix a crash that could happen when saving an object to the cache after some types of schema changes (#3636)
    • Escape reserved enum value names ("name" and "ordinal") (#3629)
    • Do not crash when trying to send to a closed websocket (#3638)

    🖋️ Better escaping for Kotlin codegen

    The escaping of Kotlin keywords used in field names now uses Kotlin's backtick escaping (`keyword`) convention instead of suffixing an underscore (keyword_). This could impact the generated code in your projects if a schema contains such fields. (#3630)

    ⚙️ [breaking] API changes

    Before going stable, the public API has been tweaked to ensure consistency.

    Uniformize Upload creation (#3613)

    Creating an Upload used to be possible by calling Upload.fromXyz() methods and now has been changed to use a Builder API which is more consistent with the rest of the API:

    // Before
    val upload = Upload.fromSource(okioSource)
    // or if you're on the JVM
    val upload = Upload.fromFile(file)
    
    // After
    val upload = DefaultUpload.Builder()
        .content(bufferedSource)
        // or if you're on the JVM
        .content(file)
        .build()
    

    Simplify Automatic Persisted Queries configuration (#3622)

    The method to enable or disable Automatic Persisted Queries on a specific call has been renamed to a more meaningful name:

    // Before
    val response = apolloClient.query(HeroNameQuery())
        .hashedQuery(false)
        .execute()
    
    // After
    val response = apolloClient.query(HeroNameQuery())
        .enableAutoPersistedQueries(false)
        .execute()
    
    

    Remove temporarily deprecated methods (#3632)

    During the course of the alpha and beta, a number of APIs have been evolving, and to allow a smooth transition by early adopters, some early APIs have been marked as deprecated in favor of new ones.

    Now that we are soon reaching a stable API, it is time to remove these early APIs.

    This means if you were using 3.0.0-beta04 or earlier you may want to first review the deprecation warnings and update your code to use the newer APIs, before upgrading to this version.

    Other changes

    • Should you need to create an ApolloResponse, you can now do so by using a Builder API (#3608)
    • Ast, Compiler and MockServer modules have been marked as experimental to reflect the fact that they haven't been widely used as of now and therefore their APIs could evolve in the future (#3614)
    • Some overloads were removed in APIs related to JSON parsing/writing to simplify these APIs. Now all of these APIs take an Okio BufferedSource as input. (#3620)
    • The actual implementations of HttpEngine (OkHttpEngine, NSURLSessionHttpEngine, and KtorHttpEngine) have all been renamed to DefaultHttpEngine for consistency (#3617)

    ☕️ Java Interop improvements

    • The built-in adapters are now usable in a more Java-friendly way (#3607):
    // Before
    String result = StringAdapter.INSTANCE.fromJson(jsonReader,CustomScalarAdapters.Empty);
    
    // After
    String result = Adapters.StringAdapter.fromJson(jsonReader,CustomScalarAdapters.Empty);
    
    • Correctly declare throwing IOException in Adapter APIs, making it possible to catch it in Java code (#3603)

    👷 All Changes

    • Do not crash when trying to send to a closed websocket (#3638)
    • URLEncode more characters for NSURL to not crash (#3637)
    • Fix collecting fields on new schema types (#3636)
    • Remove temporarily deprecated methods (#3632)
    • Differentiate escaping of Java or Kotlin keywords (#3630)
    • Escape reserved enum value names ("name" and "ordinal") (#3629)
    • Move the HTTP cache to a HttpInterceptor (#3624)
    • Simplify APQ configuration (#3622)
    • Cleanup overloads (#3620)
    • 🙅 No constructor fun (#3617)
    • Mark Ast, Compiler and MockServer modules as experimental (#3614)
    • Uniformize Upload creation (#3613)
    • 🧼 🪣 Polishing of the ApolloResponse API (#3608)
    • Make builtin scalar adapters easier to call from Java (#3607)
    • Fix CustomTypeAdapter compat (#3604)
    • Use kotlin.Throws (#3603)
    Source code(tar.gz)
    Source code(zip)
  • v3.0.0-beta04(Nov 24, 2021)

    This version is planned to be the last beta of Apollo Android 3 before a release candidate 🚀. It mainly focuses on stabilization and tweaks to the public API, makes it easier to work with the Java9 module system, and fixes a few issues.

    ⚙️ [breaking] API changes

    Before going stable, we tweaked the public API to ensure consistency. The following methods have been renamed:

    | Before | After | |--------------------------|-------------------------| | ApolloClient.mutate() | ApolloClient.mutation() | | ApolloClient.subscribe() | ApolloClient.subscription() | | ApolloSubscriptionCall.execute() | ApolloSubscriptionCall.toFlow() |

    In order to better support Java 9 and remove split packages, the following classes have been moved:

    | Before | After | |--------------------------|-------------------------| | com.apollographql.apollo3.cache.ApolloCacheHeaders | com.apollographql.apollo3.cache.normalized.api.ApolloCacheHeaders | | com.apollographql.apollo3.cache.CacheHeaders | com.apollographql.apollo3.cache.normalized.api.CacheHeaders | | com.apollographql.apollo3.cache.CacheHeaders.Builder | com.apollographql.apollo3.cache.normalized.api.CacheHeaders.Builder | | com.apollographql.apollo3.cache.CacheHeaders.Companion | com.apollographql.apollo3.cache.normalized.api.CacheHeaders.Companion | | com.apollographql.apollo3.cache.normalized.CacheKey | com.apollographql.apollo3.cache.normalized.api.CacheKey | | com.apollographql.apollo3.cache.normalized.CacheKey.Companion | com.apollographql.apollo3.cache.normalized.api.CacheKey.Companion | | com.apollographql.apollo3.cache.normalized.CacheKeyResolver | com.apollographql.apollo3.cache.normalized.api.CacheKeyResolver | | com.apollographql.apollo3.cache.normalized.CacheResolver | com.apollographql.apollo3.cache.normalized.api.CacheResolver | | com.apollographql.apollo3.cache.normalized.DefaultCacheResolver | com.apollographql.apollo3.cache.normalized.api.DefaultCacheResolver | | com.apollographql.apollo3.cache.normalized.FieldPolicyCacheResolver | com.apollographql.apollo3.cache.normalized.api.FieldPolicyCacheResolver | | com.apollographql.apollo3.cache.normalized.NormalizedCache.Companion | com.apollographql.apollo3.cache.normalized.api.NormalizedCache.Companion | | com.apollographql.apollo3.cache.normalized.NormalizedCacheFactory | com.apollographql.apollo3.cache.normalized.api.NormalizedCacheFactory | | com.apollographql.apollo3.cache.normalized.ReadOnlyNormalizedCache | com.apollographql.apollo3.cache.normalized.api.ReadOnlyNormalizedCache | | com.apollographql.apollo3.cache.normalized.Record | com.apollographql.apollo3.cache.normalized.api.Record | | com.apollographql.apollo3.cache.normalized.RecordFieldJsonAdapter | com.apollographql.apollo3.cache.normalized.api.RecordFieldJsonAdapter | | com.apollographql.apollo3.cache.normalized.MemoryCache | com.apollographql.apollo3.cache.normalized.api.MemoryCache | | com.apollographql.apollo3.cache.normalized.MemoryCacheFactory | com.apollographql.apollo3.cache.normalized.api.MemoryCacheFactory | | com.apollographql.apollo3.cache.normalized.OperationCacheExtensionsKt | com.apollographql.apollo3.cache.normalized.api.OperationCacheExtensionsKt |

    Other renames

    | Before | After | |--------------------------|-------------------------| | com.apollographql.apollo3.api.ApolloExperimental | com.apollographql.apollo3.annotations.ApolloExperimental | | com.apollographql.apollo3.api.ApolloInternal | com.apollographql.apollo3.annotations.ApolloInternal | | com.apollographql.apollo3.cache.normalized.ObjectIdGenerator | com.apollographql.apollo3.cache.normalized.api.CacheKeyGenerator | | com.apollographql.apollo3.cache.normalized.ObjectIdGeneratorContext | com.apollographql.apollo3.cache.normalized.api.CacheKeyGeneratorContext | | com.apollographql.apollo3.network.http.OkHttpEngine | com.apollographql.apollo3.network.http.DefaultHttpEngine |

    Renames in ApolloCall and ApolloClient (#3594)

    ApolloClient's mutate and subscribe methods have been renamed to mutation and subscription respectively. This creates a more consistent API by reusing the GraphQL specification terminology. Also, mutate(), subscribe() could be misleading as despite being verbs, no action is done until execute() is called. Using mutation()/subscription() hints that execute() is required as a terminal operation.

    // Before
    val data = client.mutate(MyMutation()).execute()
    
    // After
    val data = client.mutation(MyMutation()).execute()
    

    Also, ApolloSubscriptionCall.execute() has been renamed to ApolloSubscriptionCall.toFlow() to make it clearer that it returns a cold Flow that can be collected several times:

    // Before
    val flow = client.subscription(MySubscription).execute()
    
    // After
    val flow = client.subscription(MySubscription).toFlow()
    

    Rename ObjectId to CacheKey (#3575)

    CacheKeys were sometimes referred to as Cache ids, Object ids, despite all of them being the same concept (the key of an object in the cache). For consistency inside the Apollo Android codebase and with the iOS and Web clients, CacheKey is going to be used everywhere moving forward

    // Before
    val objectIdGenerator = object : ObjectIdGenerator {
      override fun cacheKeyForObject(obj: Map<String, Any?>, context: ObjectIdGeneratorContext): CacheKey? {
        // Retrieve the id from the object itself
        return CacheKey(obj["id"] as String)
      }
    }
    
    val apolloClient = ApolloClient.Builder()
        .serverUrl("https://...")
        .normalizedCache(
            normalizedCacheFactory = cacheFactory,
            objectIdGenerator = objectIdGenerator,
        )
        .build()
    
    // After
    val cacheKeyGenerator = object : CacheKeyGenerator {
      override fun cacheKeyForObject(obj: Map<String, Any?>, context: CacheKeyGeneratorContext): CacheKey? {
        // Retrieve the id from the object itself
        return CacheKey(obj["id"] as String)
      }
    }
    
    val apolloClient = ApolloClient.Builder()
        .serverUrl("https://...")
        .normalizedCache(
            normalizedCacheFactory = cacheFactory,
            cacheKeyGenerator = cacheKeyGenerator,
        )
        .build()
    

    dataAssertNoErrors (#3534)

    To reflect more accurately what this method does, dataOrThrow is now dataAssertNoErrors.

    Kotlin enums generation by default (#3551)

    Apollo Android can either generate GraphQL enums as Kotlin enums or sealed classes. In previous 3.0 releases, the default was to generate sealed classes but it is now enums, as this will be more expected, works better with Swift, and is consistent with the 2.x behavior. To fallback to the previous behaviour of always generating sealed classes, use the sealedClassesForEnumsMatching Gradle option:

    apollo {
      sealedClassesForEnumsMatching.set(listOf(".*"))
    }
    

    Improve java usability (#3576 and #3509)

    Using Apollo Android from Java should be less cumbersome thanks to a few API tweaks in this release. For example, to set up a normalized cache:

    // Before
    builder = ClientCacheExtensionsKt.normalizedCache(
        builder,
        new MemoryCacheFactory(10 * 1024 * 1024, -1),
        TypePolicyObjectIdGenerator.INSTANCE,
        FieldPolicyCacheResolver.INSTANCE,
        false
        );
    
    // After
        NormalizedCache.configureApolloClientBuilder(
        builder,
        new MemoryCacheFactory(10 * 1024 * 1024, -1),
        );
    

    Other noteworthy tweaks (#3509, #3538, #3557, #3598)

    • HttpNetworkTransport and WebSocketNetworkTransport now use the Builder pattern for instantiation
    • FlowDecorator have been removed from ApolloClient as ApolloInterceptor can be used instead
    • httpHeader extension is now addHttpHeader
    • We also made sure with this release that classes that are not meant to be used outside the library are marked as internal.

    ✨ [new] Java Platform Module System (JPMS) support (#3558)

    Apollo Android now publishes jar files containing the Automatic-Module-Name property and non-split packages. This change makes it easier to work with Apollo Android from a Java 9+ modularized application.

    ✨ [new] Add fallback adapters (#3582)

    You no longer need to register any of the built-in adapters after declaring a custom scalar type that maps to a built-in type (Int, Long, String, etc.).

    For instance, when declaring this custom scalar type:

    apollo {
      customScalarsMapping = [
          "MyCustomNumber": "kotlin.Long"
      ]
    }
    

    There is no need to call addCustomScalarAdapter on the builder anymore, as since it is for a kotlin.Long it will automatically fall back to the built-in LongAdapter.

    🪲 [fixes] Optimistic cache and Gradle plugin (#3577, #3496)

    • Fix an issue where the optimistic cache data was not reverted when an error happens
    • The Gradle plugin now correctly works without the Kotlin Plugin

    👷 All Changes

    • make Guard and NonMainWorker internal (#3600)
    • Tweak visibility of apollo-api symbols (#3598)
    • Make a few classes internal (#3591)
    • Make a few classes either internal or @ApolloInternal (#3590)
    • Check internal on http-cache (#3589)
    • Renames in ApolloCall and ApolloClient (#3594)
    • Add apollo-annotations (#3588)
    • Add fallback adapters (#3582)
    • Merge main in dev-3.x (#3580)
    • Improve java usability (#3576)
    • Optimistic cache fixes (#3577)
    • Add 2.x compat mode for useHttpGetMethodForQueries and useHttpGetMethodForPersistedQueries (#3578)
    • Rename ObjectId to CacheKey (#3575)
    • Handle experimental opt ins (#3565)
    • Kotlin 1.6 (#3563)
    • JPMS support (#3558)
    • Rename httpHeader extensions to addHttpHeader (#3557)
    • Go back to generating GraphQL enums as Kotlin enums by default (#3551)
    • Relocate the kotlin-stdlib in the Gradle Plugin (#3542)
    • Add "UI testing" and remove flowDecorators (#3538)
    • Allow Delete/Continue/Replace during AST transformations (#3545)
    • Tweak the errors doc and add ApolloResponse.dataAssertNoErrors (#3534)
    • update Gradle and wrapper to 7.3 (#3535)
    • Mark Test Builders are experimental (#3511)
    • Add more Builders and other API tuning ✨ (#3509)
    • Make the Gradle plugin work without the Kotlin Plugin (#3496)
    Source code(tar.gz)
    Source code(zip)
  • v2.5.11(Nov 12, 2021)

    Version 2.5.11 is a maintenance release with fixes for registerApolloOperations and query batching.

    💜 Many thanks to @AOrobator and @rocketraman for their awesome contributions and feedback !💜

    👷 All Changes

    • Added toString method for Input by @AOrobator in https://github.com/apollographql/apollo-android/pull/3427
    • Make safelistingHash closer to its apollo-tooling counterpart by @martinbonnin in https://github.com/apollographql/apollo-android/pull/3471
    • Make sure Response is always closed when batching by @martinbonnin in https://github.com/apollographql/apollo-android/pull/3541

    Full Changelog: https://github.com/apollographql/apollo-android/compare/v2.5.10...v2.5.11

    Source code(tar.gz)
    Source code(zip)
  • v3.0.0-beta03(Nov 5, 2021)

    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.

    👷 All Changes

    • Fix concurrent accesses to the SQLite database (#3503)
    Source code(tar.gz)
    Source code(zip)
  • v3.0.0-beta02(Nov 3, 2021)

    This version introduces fluent APIs on operations, more multiplatform targets, more compatibility helpers to ease transition from v2.x, and other fixes.

    ✨ [new and breaking] Fluent APIs (#3447)

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

    ✨ [new] New multiplatform targets (#3487)

    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!

    ✨ [new] Sealed interfaces in generated code (#3448)

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

    ✨ [new] Version 2 compatibility helpers

    To ease transition from 2.x, this release provides:

    • a CustomTypeAdapter that can be used for custom scalars in the same way as in 2.x
    • an Input helper that will map to 3.x Optional automatically

    These helpers are deprecated and are to be used only as a temporary measure - they will be removed in a future version.

    💙 External contributors

    Thanks to @davidec-twinlogix, @pauldavies83 @nachtien and @Pitel for their awesome contributions!

    👷 All Changes

    • Add a "compat" v2 CustomTypeAdapter to v3 Adapter API (#3482)
    • Add a few targets (#3487)
    • Add parsing of non-standard Error fields (#3485)
    • Resolve name clashes the same way as in 2.x (#3486)
    • Make the packageName error more explicit for users that are migrating (#3477)
    • Fix pointer use after free (#3478)
    • Add Apple Silicon iOS Simulator Targets (#3481)
    • Check minimum Kotlin version in the plugin (#3475)
    • Migrate HttpRequest With-ers to Builders (#3474)
    • Add .customScalarAdapter(CustomScalarAdapters) on ApolloClient.Builder (#3472)
    • Bump KSP and Okio to stable 🎉 (#3473)
    • [RFC] Fluent query API (#3447)
    • Generate sealed interfaces in response based codegen (#3448)
    • Add MySealedClass.knownValues() (#3465)
    • Added Long support to RecordFieldJsonAdapter (#3468)
    • Add an iOSX64 test and publish apollo-testing-support for ios (#3463)
    • Add customTypesMapping for backward compatibility (#3452)
    • Add Input backward compat layer (#3456)
    • Rename include to includes (#3451)
    Source code(tar.gz)
    Source code(zip)
  • v3.0.0-beta01(Oct 25, 2021)

    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

    • Mutations over WebSocket (graphql-ws protocol) may hang indefinitely … by @dchappelle in https://github.com/apollographql/apollo-android/pull/3383
    • Fix nanosecond conversion on native by @martinbonnin in https://github.com/apollographql/apollo-android/pull/3386
    • Support Ping/Pong messages for graphql-transport-ws (#3291) by @dchappelle in https://github.com/apollographql/apollo-android/pull/3401
    • WebSockets: better separate common code and protocol-specific code by @martinbonnin in https://github.com/apollographql/apollo-android/pull/3405
    • Bump SqlDelight by @martinbonnin in https://github.com/apollographql/apollo-android/pull/3407
    • Bump Kotlin to 1.5.31 by @martinbonnin in https://github.com/apollographql/apollo-android/pull/3414
    • Allow isFromCache on all ApolloResponses by @martinbonnin in https://github.com/apollographql/apollo-android/pull/3416
    • Update ApolloClient and ApolloRequest APIs from With-ers to Builders by @BoD in https://github.com/apollographql/apollo-android/pull/3404
    • JavaScript by @Pitel in https://github.com/apollographql/apollo-android/pull/3208
    • Add Test Builders by @martinbonnin in https://github.com/apollographql/apollo-android/pull/3415
    • Reintroduce sealedClassesForEnumsMatching by @martinbonnin in https://github.com/apollographql/apollo-android/pull/3435
    • Add generateOptionalOperationVariables gradle param by @martinbonnin in https://github.com/apollographql/apollo-android/pull/3438
    • Add ApolloClient.builder() method for v2 compat by @BoD in https://github.com/apollographql/apollo-android/pull/3441

    New Contributors

    • @Pitel made their first contribution in https://github.com/apollographql/apollo-android/pull/3208

    Full Changelog: https://github.com/apollographql/apollo-android/compare/v3.0.0-alpha07...v3.0.0-beta01

    Source code(tar.gz)
    Source code(zip)
  • v2.5.10(Oct 15, 2021)

    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 !💜

    ✨[new] Mutiny support (#3213)

    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

    ✨[new] 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.

    👷 All Changes

    • refactor: RxJava2/3 support by @aoudiamoncef in https://github.com/apollographql/apollo-android/pull/3166
    • Remove duplicate ExecutionContext by @martinbonnin in https://github.com/apollographql/apollo-android/pull/3213
    • feat: add Mutiny support by @aoudiamoncef in https://github.com/apollographql/apollo-android/pull/3198
    • Updated coroutines for use native-mt version by @ProVir in https://github.com/apollographql/apollo-android/pull/3330
    • Increase Json nesting to 256 by @martinbonnin in https://github.com/apollographql/apollo-android/pull/3334
    • Give a hint at errorPayload by @martinbonnin in https://github.com/apollographql/apollo-android/pull/3381
    • Workaround wrong input field default values by @martinbonnin in https://github.com/apollographql/apollo-android/pull/3398
    • do not crash when trying to indent the GraphQL document by @martinbonnin in https://github.com/apollographql/apollo-android/pull/3399
    • Add ./gradlew push${MainService}ApolloOperations by @martinbonnin in https://github.com/apollographql/apollo-android/pull/3403
    • Operation Registry: normalize queries before computing the hash by @martinbonnin in https://github.com/apollographql/apollo-android/pull/3406

    New Contributors

    • @ProVir made their first contribution in https://github.com/apollographql/apollo-android/pull/3330
    • @jgarrow made their first contribution in https://github.com/apollographql/apollo-android/pull/3346
    • @BoD made their first contribution in https://github.com/apollographql/apollo-android/pull/3396

    Full Changelog: https://github.com/apollographql/apollo-android/compare/v2.5.9...v2.5.10

    Source code(tar.gz)
    Source code(zip)
Owner
Apollo GraphQL
A community building flexible open source tools for GraphQL.
Apollo GraphQL
Show weather data for the current location [Apollo Agriculture Interview Solution], for the Senior Android Engineer Role

Apollo Agriculture Android Take Home Assignment Writing Apollo Agriculture App using Android Architecture Components, in 100% Kotlin, using Android Je

Juma Allan 23 Nov 23, 2022
Clean MVVM with eliminating the usage of context from view models by introducing hilt for DI and sealed classes for displaying Errors in views using shared flows (one time event), and Stateflow for data

Clean ViewModel with Sealed Classes Following are the purposes of this repo Showing how you can remove the need of context in ViewModels. I. By using

Kashif Mehmood 22 Oct 26, 2022
RecyclerView Adapter Library with different models and different layouts as convenient as possible.

RecyclerView Presenter Convenience library to handle different view types with different presenters in a single RecyclerView. How to install repositor

Jan Rabe 86 Dec 26, 2022
Mogen - Converts Kotlin models to other languages

Mogen is a small library that converts Kotlin's models to other programming lang

elevup 3 Jun 8, 2022
Simplify mutating "immutable" state models

Mutekt (Pronunciation: /mjuːˈteɪt/, 'k' is silent) "Simplify mutating "immutable" state models" Generates mutable models from immutable model definiti

Shreyas Patil 179 Nov 30, 2022
GraphQL based Jetpack Compose and SwiftUI Kotlin Multiplatform sample

GraphQL based Jetpack Compose and SwiftUI Kotlin Multiplatform sample

John O'Reilly 151 Jan 3, 2023
Kotlin-client-dsl - A kotlin-based dsl project for a (Client) -> (Plugin) styled program

kotlin-client-dsl a kotlin-based dsl project for a (Client) -> (Plugin) styled p

jackson 3 Dec 10, 2022
Create an application with Kotlin/JVM and Kotlin/JS, and explore features around code sharing, serialization, server- and client

Practical Kotlin Multiplatform on the Web 본 저장소는 코틀린 멀티플랫폼 기반 웹 프로그래밍 워크숍(강좌)을 위해 작성된 템플릿 프로젝트가 있는 곳입니다. 워크숍 과정에서 코틀린 멀티플랫폼을 기반으로 프론트엔드(front-end)는 Ko

SpringRunner 14 Nov 5, 2022
Create an application with Kotlin/JVM and Kotlin/JS, and explore features around code sharing, serialization, server- and client

Building a Full Stack Web App with Kotlin Multiplatform 본 저장소는 INFCON 2022에서 코틀린 멀티플랫폼 기반 웹 프로그래밍 핸즈온랩을 위해 작성된 템플릿 프로젝트가 있는 곳입니다. 핸즈온 과정에서 코틀린 멀티플랫폼을

Arawn Park 19 Sep 8, 2022
Server Sent Events (SSE) client multiplatform library made with Kotlin and backed by coroutines

OkSSE OkSSE is an client for Server Sent events protocol written in Kotlin Multiplatform. The implementation is written according to W3C Recommendatio

BioWink GmbH 39 Nov 4, 2022
Kotlin Multiplatform is an SDK for cross-platform mobile development, which enables teams to use the same business logic in both Android and iOS client applications.

Kotlin Multiplatform is an SDK for cross-platform mobile development, which enables teams to use the same business logic in both Android and iOS client applications.

Chris Russell 1 Feb 11, 2022
Unofficial Android client for dev.to. Open source and free

Dev.to Android by Android Broadcast Unofficial Android client for dev.to Technologies Kotlin Gradle Kotlin DSL Kotlin Coroutines OkHttp + Retrofit kot

Android Broadcast 76 Nov 30, 2022
An open source GitHub Android client app, faster and concise.

An open-source GitHub Android client app, faster and concise.

30度的射线 4.1k Dec 26, 2022
A FOSS Git multiplatform client based on Compose and JGit.

Gitnuro A FOSS Git client based on (Jetbrains) Compose and JGit. The main goal of Gitnuro is to provide a multiplatform open source Git client without

Abdelilah El Aissaoui 238 Dec 24, 2022
🐘 Mastodon client for Android, iOS and Desktop (JVM)

MastodonX A multiplatform Mastodon client written in Kotlin for the amazing androiddev.social community and everyone else who enjoys #Fediverse Join o

null 372 Dec 28, 2022
Android Spinner Dialog Library supported on both Java and Kotlin, Use for single or multi selection of choice

SpinnerDialog Android Spinner Dialog Library, Use for single or multi selection of choice Android UI Download To include SpinnerDialog in your project

Hamza Khan 55 Sep 15, 2022
StaticLog - super lightweight static logging for Kotlin, Java and Android

StaticLog StaticLog is a super lightweight logging library implemented in pure Kotlin (https://kotlinlang.org). It is designed to be used in Kotlin, J

Julian Pfeifer 28 Oct 3, 2022
Auto-generate the fastest possible Parcelable implementations for Java and Kotlin

This project is deprecated It will still be maintained, but no new features will be added. Please use Parcelize, as it is the official way of generati

Bradley Campbell 492 Nov 17, 2022
Kotlin and Java API for generating .swift source files.

SwiftPoet SwiftPoet is a Kotlin and Java API for generating .swift source files. Source file generation can be useful when doing things such as annota

Outfox 232 Jan 2, 2023