Skip to content

Releases: apollographql/apollo-kotlin

v4.0.0-beta.4

12 Dec 13:51
@BoD BoD
e00841c
Compare
Choose a tag to compare

✨ Initial Wasm support (#5458)

This release adds initial support for WebAssembly by adding the wasmJs target.

Executing queries/mutations is working but this target is
experimental (Kotlin/Wasm is Alpha) and has multiple limitations:

  • No WebSockets
  • No caching
  • No support for WASI or NodeJS

🪲 Bug fix

Downloading a schema from introspection (./gradlew downloadServiceSchemaFromIntrospection) got broken in the previous release (#5449) and is now fixed.

👷‍ All changes

v4.0.0-beta.3

05 Dec 19:40
b6606e4
Compare
Choose a tag to compare

Many thanks @chris-hatton and @sdfgsdfgd for contributing this version 💙

⚠️ we're aware of a regression in downloadApolloSchema, we'll make a new release soon.

🧩 IDE plugin: in-memory cache support

The normalized cache viewer can now display the contents of your in-memory cache. To do so, it relies on a
debug server that you need to run in your debug builds:

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

if (BuildConfig.DEBUG) {
  ApolloDebugServer.registerApolloClient(apolloClient)
}

You can read more about it in the "Apollo debug server" documentation page.

🎣 Experimental @catch and @semanticNonNull support

@catch makes it possible to model GraphQL errors as FieldResult Kotlin classes giving you inline access to errors:

query GetUser {
  user {
    id
    # map name to FieldResult<String?> instead of stopping the parsing
    name @catch
    avatarUrl
  }
}

@semanticNonNull is a better @nonnull. @semanticNonNull makes it possible to mark a field as null only on error. The matching Kotlin property is then generated as non-null:

# mark User.name as semantically non-null
extend type User @semanticNonNull(field: "name")

Both those directives are experimental and require opt-in of the nullability directives

You can read more about them in the "handle nullability" documentation page.

1️⃣ Experimental @oneOf support

@oneOf introduces input polymorphism to GraphQL:

input PetInput @oneOf {
  cat: CatInput
  dog: DogInput
  fish: FishInput
}

input CatInput { name: String!, numberOfLives: Int }
input DogInput { name: String!, wagsTail: Boolean }
input FishInput { name: String!, bodyLengthInMm: Int }

type Mutation {
  addPet(pet: PetInput!): Pet
}

With @oneOf, only one of cat, dog or fish can be set.

@oneOf support is automatically enabled if your schema has the @oneOf directive definition.

You can read more about it in the @oneOf RFC

👷‍ All changes

[all] @oneOf support (#5394, #5388)
[all] @catch and @semanticNonNull support (#5405)
[all] Take default values into account when computing field cache keys (#5384)
[all] Bump Kotlin to 2.0.0-Beta1 (#5373)

[IJ Plugin] Add 'Input class constructor issue' inspection (#5427)
[IJ plugin] Update v3->v4 migration following API tweaks (#5421)
[IJ Plugin] Report invalid oneOf input object builder uses (#5416)
[IJ Plugin] Add inspection for @oneOf input type constructor invocation (#5395)
[IJ plugin] Make the refresh button work with all normalized cache sources. (#5400)
[IJ Plugin] Cache viewer: take numbers into account in key sorting (#5396)
[IJ Plugin] Bump pluginUntilBuild to 233 (#5377)
[IJ Plugin] Telemetry: don't use a libraries changed listener (#5361)
[IJ Plugin] Cache viewer: add cache size to selector (#5357)
[IJ plugin] Use apollo-debug-server to retrieve normalized caches (#5348)
[IJ plugin] Cache viewer: "Pull from Device" modal dialog instead of action menu (#5333)
[IJ Plugin] Fix v3->v4 migration with ApolloCompositeException (#5330)

[runtime] remove some of the ApolloResponse.Builders (#5426)
[runtime] Add a few symbols as ERROR deprecation for the migration (#5422)
[runtime] Add executeV3 + toFlowV3 (#5417)
[runtime] Revive dataAssertNoErrors (#5419)
[runtime] Allow no data and no exception in case of GraphQL errors (#5408)
[runtime] Expose ExecutionContext to HttpEngine and add OkHttp helpers (#5383)
[runtime] Improve deprecation messages (#5411)
[runtime] Go back to just one Adapter class (#5403)
[runtime] Fix Optional.getOrElse (#5399)

[compiler] Remove kotlin-labs-0.1 directives (#5404)
[compiler] Throw a better exception than NullPointerException if a value is missing (#5402)
[compiler] ExecutableValidationResult is returned by validateAsExecutable() and cannot be @ApolloInternal (#5406)
[compiler] Rework the IrType hierarchy (#5392)
[compiler] remove CCN (#5387)
[compiler] Remove antlr (#5336)
[compiler] Tweak description javadoc, there is no need to use the same escaping as Kotlin (#5424)

[mockserver] Support setting port for Apollo MockServer (#5389)
[mockserver] Add WebSocket support to the MockServer (#5334)
[tools] Implement 2-step introspection (#5371)
[apollo-execution] Allow to pass arguments to the root types (#5352)
[apollo-ksp] Initial support for interfaces (#5351)

v4.0.0-beta.2

23 Oct 15:54
@BoD BoD
5e30da5
Compare
Choose a tag to compare

We're continuing to progress towards the stable release of Apollo Kotlin v4 with this 2nd beta, which contains a few bug fixes and a new normalized cache viewer in the IDE plugin.

This is a great time to try out the new version and report any issues you might find!

🧩 IDE plugin: normalized cache viewer

The IDE plugin now has a graphical tool to inspect a normalized cache database. It lets you browse the records and see their contents.
This is useful to debug cache issues, or to understand how the normalized cache works.

The tool is available from View | Tool Windows | Apollo Normalized Cache.

More information about the plugin can be found here.

👷‍ All changes

  • Fragment variables: fix false warning about unused variables (#5290)
  • Fix reading fragment with include directives from the cache (#5296)
  • Fix partial data throwing with useV3ExceptionHandling and normalized cache (#5313)
  • Unbreak benchmarks (#5284)
  • Bump to gradle 8.4 and IJGP 1.16.0 (#5286)
  • Add apollo-execution and apollo-ksp (#5281)
  • [IJ plugin] Normalized cache viewer: UI (#5298)
  • Fix build (#5301)
  • Bump to Kotlin 1.9.20-RC (#5300)
  • [IJ plugin] Telemetry: networking (#5285)
  • [IJ plugin] Cache viewer: record quick filter (#5302)
  • Update release script to update versions in IJ plugin (#5303)
  • MockServer API cleanup (#5307)
  • Remove some warnings (#5308)
  • Use the default hierarchy template (#5309)
  • [IJ plugin] Cache viewer: open/read db file (#5306)
  • [IJ plugin] Cache viewer: add back/forward buttons, and copy action (#5310)
  • Fix NSURL tests on recent apple OSes (#5315)
  • [IJ plugin] Cache viewer: pull file from attached devices (#5314)
  • Make more of MockServer common code, only abstract the socket part (#5316)

v4.0.0-beta.1

02 Oct 13:49
@BoD BoD
167acd9
Compare
Choose a tag to compare

The first beta of the next major version of Apollo Kotlin is here!

While there still may be a few API changes before the stable release, we are getting close and this is a great time to try out the new version and report any issues you might find!

💙️ External contributors

Many thanks to @baconz and @hbmartin for their awesome contributions to this release!

❗️ Schema Nullability Extensions (#5191)

The GraphQL community is working hard at making it easier to work with nullability in GraphQL.

In Apollo Kotlin, it is now possible to change the nullability of fields and list elements at the schema level using schema extensions. This is useful if you believe the schema made a field nullable for error reasons only and you don't want to handle those errors. In these cases, the whole query will return as an error.

Given the following SDL:

# schema.graphqls
type Query {
  random: Int
  list: [String]
  required: Int!
}

You can extend it like so:

# extra.graphqls
extend type Query {
  # make random non-nullable
  random: Int!
  # make list and list items non-nullable
  list: [String!]!
  # make required nullable
  required: Int
  # add a new field
  new: Float
}

📜️ Code generation

generateMethods option to control which model methods are generated (#5212)

By default all Kotlin models, operations, fragments, and input objects are generated as data classes. This means that the Kotlin compiler will
auto-generate toString, equals hashCode, copy and componentN. If you don't think you need all of those
methods, and/or you are worried about the size of the generated code, you can now choose which methods to generate with the generateMethods option:

apollo {
  service("service") {
    // Generates equals/hashCode
    generateMethods.set(listOf("equalsHashCode"))
    // Also generates toString, equals, and hashcode
    generateMethods.set(listOf("equalsHashCode", "toString"))
    // Only generates copy
    generateMethods.set(listOf("copy"))
    // Generates data classes (the default)
    generateMethods.set(listOf("dataClass"))
  }
}

Other codegen tweaks

  • Enum.values() is no longer recommended when using Kotlin 1.9+ and the generated code now uses entries instead (#5208)
  • Deprecation warnings in generated code are suppressed (#5242)

🧩 IntelliJ plugin

  • You can now suppress reported unused fields, by adding a comment on the field, or by configuring a regex in the settings (#5195, #5197)
  • Opening an operation in Sandbox now includes all referenced fragments (#5236)

🪲 Bug fixes

  • Detect cyclic fragment references (#5229)
  • Fix Optional<V>.getOrThrow() when V is nullable (#5192)
  • useV3ExceptionHandling only throws when there are no errors populated (#5231)
  • Tweak the urlEncode algorithm (#5234)
  • Add a validation for adding keyFields on non-existent fields (#5215)
  • Fix logging when the response body is a single line (#5254)

👷‍ All changes

  • [Infra] Count tests in CI (#5181)
  • Test: remove flake (#5167)
  • Use compilations instead of multiple mpp targets for java codegen tests (#5164)
  • [IJ plugin] Add fragment usages when going to fragment declaration (#5189)
  • Add mergeExtensions and toFullSchemaGQLDocument (#5162)
  • Fix Optional<V>.getOrThrow() when V is nullable (#5192)
  • Schema Nullability Extensions (#5191)
  • [IJ plugin] Add inspection suppressor to allow suppression on fields (#5195)
  • Add PQL support to registerOperations {} (#5196)
  • Add WebSocketMockServer and tests for WebSocketEngine (#5187)
  • [IJ plugin] Add options to ignore fields when reporting unused fields (#5197)
  • Unbreak benchmarks (#5202)
  • Bump uuid and okio (#5204)
  • [IJ plugin] Update references to 4.0.0-alpha.2 to 4.0.0-alpha.3 (#5205)
  • Use entries instead of values() when using Kotlin 1.9 (#5208)
  • Add generateMethods options to control which methods are generated on "data" classes (#5212)
  • Add a validation for adding keyFields on non-existent fields (#5215)
  • Engine tests: use compilations to share logic between ktor/default engines (#5216)
  • Skip Dokka during development (#5219)
  • Introduce JsonReader.toApolloResponse (#5218)
  • Add tests for empty objects in last chunk (#5223)
  • useV3ExceptionHandling should only throw when there are no errors populated (#5231)
  • Tweak the urlencode algorithm (#5234)
  • [IJ plugin] Gather referenced fragments when opening in Apollo Sandbox (#5236)
  • Kotlin 1.9.20-Beta (#5232)
  • Suppress Kotlin warnings in generated code (#5242)
  • Add Optional.getOrElse(value) (#5243)
  • Add Error.Builder() (#5244)
  • Add APOLLO_RELOCATE_JAR and APOLLO_JVM_ONLY (#5245)
  • Detect cyclic fragment references (#5229)
  • [IJ plugin] Telemetry: collect properties (#5246)
  • Bump kotlin to 1.9.20-Beta2 (#5249)
  • [IJ plugin] Telemetry: settings and opt-out dialog (#5247)
  • [IJ plugin] Telemetry: add IDE/plugin related properties and events (#5250)
  • Fix cyclic fragment detection (#5252)
  • [IJ plugin] Add an ErrorReportSubmitter (#5253)
  • Logging a single line response body by @hbmartin in #5254
  • [IJ plugin] Schedule send telemetry (#5256)
  • Allow MapJsonReader to read non-Map instances (#5251)
  • [IJ plugin] Fix a crash when loading plugin (#5260)
  • Tweaks for K2 (#5259)
  • Update apollo published (#5263)

v4.0.0-alpha.3

08 Aug 17:26
fec1564
Compare
Choose a tag to compare

A lot of additions to the IntelliJ plugin as well as a new GraphQL parser, a new Ktor multiplatform engine and more!

💙 External contributors 💙

Apollo Kotlin wouldn't be where it is today without the awesome feedback, discussions and contributions from community members. Specifically in this release, we want to give a huge THANK YOU to: @Emplexx, @sonatard, @yt8492, @mayakoneval, @Meschreiber, @pcarrier and @ashare80

🧩 IntelliJ plugin

👓 Unused field inspection (#5069)

The IntelliJ plugin now detects unused fields in your queries and greys them out:

Screen.Recording.2023-07-06.at.15.15.13.mov

v4 migration

The IntelliJ plugin can migrate most of your codebase to v4. To try it out, go to:

Tools -> Apollo -> Migrate to Apollo Kotlin 4

Because Kotlin is such a rich language and we can't account for all possible ways to configure your build, you might have to do some manual tweaks after the migration. But the plugin should handle most of the repetitive tasks of migrating.

☁️ Schema download (#5143)

If you configured introspection, you can now download your schema directly from IntelliJ

📖 documentation

The IntelliJ plugin now has its own dedicated documentation page.

Consult it to find out everything you can do with the plugin as well as installation instructions.

🌳 Multiplatform Apollo AST (#5047)

Apollo AST, the GraphQL parser powering Apollo Kotlin is now a manually written recursive descent parser, compared to an automatically generated Antlr parser before.
Benchmarks show a x2 to x3 speed improvement and the parser also now supports all platforms Apollo Kotlin supports.

❗❓ Initial Client Controlled Nullability (CCN) support (#5118)

Client Controlled Nullability (CCN) is a GraphQL specification RFC aiming at making it easier to work with GraphQL in type safe languages like Kotlin and Swift.

To use CCN, use the ! and ? CCN modifiers in your queries:

query GetUser {
  user {
    id
    # name is required to display the user
    name!
    # phoneNumber is optional
    phoneNumber?
  }
}

The RFC is still in early stages and requires server support. The API and final shape of the RFC might still change. By adding support in Apollo Kotlin, we're hoping to unblock potential users and gather real life feedbacks helping the proposal move forward.

📡 Ktor engine (#5142)

Apollo Kotlin now ships a apollo-engine-ktor that you can use to replace the default HTTP and WebSocket engines of ApolloClient. To use it, add apollo-engine-ktor to your dependencies:

dependencies {
  implementation("com.apollographql.apollo3:apollo-engine-ktor")
}

And configure your client to use it:

val apolloClient = ApolloClient.Builder()
    .serverUrl("https://example.com/graphql")
    .httpEngine(KtorHttpEngine())
    .webSocketEngine(KtorWebSocketEngine())
    .build()

👷 generateInputBuilders (#5146)

For Kotlin codegen, Apollo Kotlin relied on constructors with default arguments. While this works well in most cases, default arguments lack the ability to distinguish between null and absent meaning you have to wrap your values in Optional before passing them to your constructor. If you had a lot of values, it could be cumbersome:

val input = SignupMemberInput(
    dob = Utils.changeDateFormat(user.dobMMDDYYYY, "MM/dd/yyyy", "yyyy-MM-dd"),
    firstName = Optional.Present(user.firstName),
    lastName = user.lastName,
    ssLast4 = Optional.Present(user.ssnLastFour),
    email = user.email,
    cellPhone = Optional.Present(user.phone),
    password = user.password,
    acceptedTos = true,
    formIds = Optional.Present(formIds),
    medium = Optional.Present(ConsentMediumEnum.android)
)

To generate Kotlin Builders, set generateInputBuilders to true in your Gradle file:

apollo {
  service("api") {
    packageName.set("com.example")

    generateInputBuilders.set(true)
  }
}

With Builders, the same above code can be written in a more fluent way:

val input = SignupMemberInput.builder().apply {
    dob(Utils.changeDateFormat(user.dobMMDDYYYY, "MM/dd/yyyy", "yyyy-MM-dd"))
    firstName(user.firstName)
    lastName(user.lastName)
    ssLast4(user.ssnLastFour)
    email(user.email)
    cellPhone(user.phone)
    password(user.password)
    acceptedTos(true)
    formIds(formIds)
    medium(ConsentMediumEnum.ANDROID)
}.build()

👷‍ All changes

  • [IJ plugin] Update platformVersion to 223 (#5166)
  • [runtime] Add Ktor Engine (#5142)
  • [tests] Add a test for field names that have the same name as an enum type (#5158)
  • [api] Remove limitation on the JSON nesting. If the JSON is way too nested, an OutOfMemory exception will happen (#5161)
  • [ast] add HasDirectives to all things with directives (#5140)
  • [compiler] add a test for types named Object (#5156)
  • [ast] Add a special comment to disable the GraphQL intelliJ plugin inspection (#5154)
  • [IJ plugin] Inspection to suggest adding an introspection block (#5152)
  • [compiler] Better KDoc escape (#5155)
  • [ast] Allow explicit CCN syntax (#5148)
  • [compiler] Add generateInputBuilders (#5146)
  • [infra] Update KotlinPoet (#5147)
  • [infra] update Gradle to 8.3-rc-3 (#5149)
  • [IJ plugin] Add a Download Schema action (#5143)
  • [runtime] Remove ChannelWrapper (#5145)
  • [IJ Plugin] Suggest Apollo 4 migration from version catalog and build.gradle.kts dependencies (#5141)
  • [IJ plugin] v3->v4 migration: add useV3ExceptionHandling(true) to ApolloClient.Builder(). (#5135)
  • [IJ plugin] Improve compat->operationBased migration (#5134)
  • [IJ plugin] Avoid a crash caught in inspection (#5139)
  • [ast] add GQLNamed and GQLDescribed on all types that have a name or a description (#5127)
  • [ast] Omit scalar definitions from SDL (#5132)
  • [infra] Use SQLDelight 2.0.0 (#5133)
  • [IJ Plugin] Don't report redefinitions of built-in types as errors (#5131)
  • [IJ plugin] v3 -> v4 migration: enum capitalization (#5128)
  • [ast] Initial CCN support (#5118)
  • [infra] Make generateSourcesDuringGradleSync opt-in now that we have the IJ plugin (#5117)
  • [compose] Catch ApolloException in toState and watchAsState (#5116)
  • [IJ plugin] v3 -> v4 migration: Gradle conf (#5114)
  • [compiler] validate query/mutation/subscription directives (#5113)
  • [cache] Move serialization outside of cache lock (#5101)
  • [infra] Use compose 1.5.0 stable (#5108)
  • [compiler] Fix "no schema found" error message (#5106)
  • [IJ plugin] v3 -> v4 migration: deprecations/renames, part 2 (#5109)
  • [infra] More Apollo AST APIs (#5104)
  • [infra] Apollo AST: add start/end instead of endColumn/endLine (#5103)
  • [IJ plugin] v3 -> v4 migration: deprecations/renames (#5099)
  • [ast] fix column computation of block strings (#5102)
  • [benchmarks] Add macrobenchmarks (#5100)
  • [IJ plugin] Migrate to Apollo Kotlin 4: dependencies (#5097)
  • [IJ plugin] Support IJ platform 232 (#5095)
  • [infra] bump ijgp (#5091)
  • [infra] remove a bunch of build workarounds (#5090)
  • [4.0 cleanups] Remove DefaultImpls everywhere (#5088)
  • [infra] Remove golatac (#5086)
  • [infra] Use SQLDelight 2.0.0-rc02 and AGP 8.0.0 (#5085)
  • [ast] Switch back the parser to Strings and add more tests (#5078)
  • [benchmarks] add graphql-java benchmark (#5077)
  • [infra] Use Kotlin 1.9.0 (#4997)
  • [ast] Turn into a mpp module and move jmh benchmark to an integration test (#5072)
  • [IJ/AS Plugin] Add unused operation and unused field inspections (#5069)
  • [ast] add endLine/endColumn (#5064)
  • [ast] Add more tests and rewrite the lexer to use bytes instead of strings (#5063)
  • [IJ plugin] Add a test for ApolloFieldInsightsInspection (#5062)
  • [IJ plugin] Add an "enclose in @defer fragment" quick fix for slow field inspection (#5061)
  • [IJ plugin] Add "Schema in .graphql file" inspection (#5059)
  • [ast] Add multiplatform apollo-ast (#5047)
  • [IJ plugin] Distinguish Apollo v3 and v4 (#5056)

v4.0.0-alpha.2

30 Jun 11:24
fe4e338
Compare
Choose a tag to compare

A new alpha with updates to the IntelliJ/Android Studio plugin and better JS interop.

🧩Navigate to GraphQL

You can now navigate from Kotlin both GraphQL or Generated code:

03-go-to-declaration.mov

See blog the blog post and installation instructions for more information.

🧩Field insights

You can now connect the IJ/AS plugin to your GraphOS account. If your backend is configured to report field traces, the plugin will display a warning for expensive fields that may be slow to fetch.

Field insights

You can configure it in your IJ/AS settings Languages & Frameworks -> GraphQL -> Apollo Kotlin. See also #5048 for a video of the setup.

🌐@jsExport

responseBased codegen can now generate models annotated with @jsExport. This allows to fetch your response using faster JS-only APIs and cast them to the generated models. See the JS interoperability documentation for more information. Many thanks to @baconz for the deep dive 💙

👷‍ All changes

  • [IJ plugin] FieldInsights (#5034)
  • [IJ plugin] Keep navigation working when using import aliases for operations and fragments (#5041)
  • [IJ plugin] Make navigation more robust when gql elements are lowercase (#5037)
  • Refactor custom scalar adapters (#4905)
  • [IJ plugin] Add an 'Open in Apollo Sandbox' action (#5022)
  • [IJ plugin] Update v3 version and codegen wording (#5015)
  • add encodeDefaults to introspection schema serializer (#5016)
  • Better error message for Kotlin objects that cannot be converted to JSON (#5011)
  • Http cache: do not cache mutations (#5014)
  • [IJ plugin] Find usages GQL -> Kotlin (#5006)
  • [IJ plugin] Add GQL -> generated Kotlin navigation (#4999)
  • [IJ plugin] Override GraphQL icons (#4980)
  • add Service.operationManifestFormat (#4981)
  • [WebSockets] Fix fan out in websocket network transport (#4972)
  • Throw inside flow in MapTestNetworkTransport (#4982)
  • [IJ plugin] Add navigation to type declaration (cmd shift b) (#4978)
  • [IJ plugin] Add navigation to input types / fields (#4968)
  • Fix jsExport Gradle annotation mismatch (#4975)
  • Generate response based code with jsExport (#4907)
  • [IJ plugin] Navigate to enum declaration (#4965)
  • remove Built-By attribute in generated jars (#4961)

v3.8.2

25 May 17:24
Compare
Choose a tag to compare

A maintenance release with bugfixes, mostly around WebSockets and subscriptions as well as a LocalTime adapter and options to work with operation manifests.

Huge THANK YOU to @baconz, @AlexHartford, @Oleur for the love they put in WebSocket contributions as well as @Jephuff for their first contribution 💙 .

👷‍ All changes

  • add Service.operationManifestFormat (#4981)
  • WebSockets: Fix fan out in websocket network transport (#4972)
  • Test: Throw inside flow in MapTestNetworkTransport (#4982)
  • Doc: Add Optional.Absent in documentation (#4979)
  • Doc: clarify that operationBased codegen is the recommendation (#4966)
  • AST: use existing as the base for copying enum values (#4943)
  • Cache: Fix deleting records in the SqlNormalizedCache with cascade-true (#4938)
  • Compiler: Fix deprecated input field usage false positive (#4935)
  • Doc: Clarify KDoc of watch() (#4914)
  • WebSockets: allow changing the serverUrl of WebSocketNetworkTransport (#4885)
  • WebSockets: accept connectionPayload lambda instead of static auth (#4855)
  • Add LocalTime adapter for Java and Kotlin (#4829)
  • Doc: Add a section about the operationBased codegen (3.x) (#4940)

v4.0.0-alpha.1

16 May 11:21
@BoD BoD
2573e94
Compare
Choose a tag to compare

This release is the first alpha of the next major version of Apollo Kotlin: 4.0.0.

This version is under development, but we want to give you a preview of what's coming, and get your early feedback. Please see the roadmap for more details about the release plan.

While version 3 changed a lot of APIs compared to version 2, version 4 should be mostly compatible with version 3. Version 4 will even keep the same package name in order to keep the number of changes low.

The error handling has changed but besides that, the version should be mostly compatible. Please consult the migration guide for all the details.

We would love to hear your feedback on this release. Please report any issues, questions, ideas, or comments on the issue tracker.

🛠️ Android Studio / IntelliJ plugin

See this page for installation instructions and more information.

This plugin for Android Studio and IntelliJ helps you work with Apollo Kotlin. It provides the following features:

  • Automatic code generation
  • Integration with the GraphQL IntelliJ Plugin
  • Navigation to GraphQL definitions
  • Helpers to migrate your project to the latest version

⚡️ ApolloResponse.exception for error handling

Error handling is an important aspect of a client library and we found it could benefit from some changes.

In particular we are moving away from throwing exceptions:

  • This improves dealing with Flows as they will no longer terminate on errors
  • It helps grouping all error handling (network, GraphQL, caching) in the same area of your code

To that effect, there is now an ApolloResponse.exception : ApolloException property, which will be present when a network error or cache miss have occurred, or when GraphQL errors are present:

val data = response.data
when {
  data != null -> {
    println("The server returned data: $data")
  }
  else -> {
    // An error happened, check response.exception for more details or just display a generic error 
    when (response.exception) {
      is ApolloGraphQLException -> // do something with exception.errors
      is ApolloHttpException -> // do something with exception.statusCode
      is ApolloNetworkException -> TODO()
      is ApolloParseException -> TODO()
      else -> // generic error
    }
  }
}

To ease the migration to v4, the v3 behavior can be restored by calling ApolloClient.Builder.useV3ExceptionHandling(true).

Feedback about this change is welcome on issue 4711.

☕️ apollo-runtime-java for better Java support

As v3 has a Kotlin and Coroutines first API, using it from Java is sometimes impractical or not idiomatic. That is why in v4 we are introducing a new Java runtime, written in Java, which provides a Java friendly API. It is callback based and doesn't depend on a third-party library like Rx.

To use it in your project, instead of the usual runtime (com.apollographql.apollo3:apollo-runtime), use the following dependency in your build.gradle[.kts] file:

implementation("com.apollographql.apollo3:apollo-runtime-java")

Then you can use the ApolloClient class from Java:

ApolloClient apolloClient = new ApolloClient.Builder()
  .serverUrl("https://...")
  .build();

apolloClient
  .query(MyQuery.builder().build())
  .enqueue(new ApolloCallback<MyQuery.Data>() {
      @Override public void onResponse(@NotNull ApolloResponse<MyQuery.Data> response) {
        System.out.prinitln(response.getData());
      }
  });

A few examples can be found in the tests.

🔃 Multi-module: automatic detection of used types

In multi-module projects, by default, all the types of an upstream module are generated because there is no way to know in advance what types are going to be used by downstream modules. For large projects this can lead to a lot of unused code and an increased build time.

To avoid this, in v3 you could manually specify which types to generate by using alwaysGenerateTypesMatching. In v4 this can now be computed automatically by detecting which types are used by the downstream modules.

To enable this, add the "opposite" link of dependencies with isADependencyOf().

// schema/build.gradle.kts
apollo {
  service("service") {
    packageName.set("schema")

    // Enable generation of metadata for use by downstream modules 
    generateApolloMetadata.set(true)

    // More options...

    // Get used types from the downstream module
    isADependencyOf(project(":feature1"))

    // You can have several downstream modules
    isADependencyOf(project(":feature2"))
  }
}
// feature1/build.gradle.kts
apollo {
  service("service") {
    packageName.set("feature1")
    
    // Get the generated schema types (and fragments) from the upstream schema module 
    dependsOn(project(":schema")) 
  }
}

v3.8.1

21 Apr 11:00
@BoD BoD
66f5495
Compare
Choose a tag to compare

This patch release contains 2 bug fixes.

👷‍ All changes

  • Add ignoreApolloClientHttpHeaders (#4838)
  • Download introspection: handle GraphQL errors (#4861)

v3.8.0

03 Apr 11:51
Compare
Choose a tag to compare

This release adds two new artifacts that contain Jetpack compose extensions amongst other fixes.

💙️ External contributors

Many thanks to @slinstacart and @hbmartin for their contributions to this release!

✨ [New] Jetpack compose extension (#4802)

You can now use the apollo-compose-support artifact:

// build.gradle.kts
dependencies {
  implementation("com.apollographql.apollo3:apollo-compose-support")
}

This artifact contains the toState() and watchAsState() extensions:

/**
 * A stateful composable that retrieves your data
 */
@OptIn(ApolloExperimental::class)
@Composable
fun LaunchDetails(launchId: String) {
    val response by apolloClient.query(LaunchDetailsQuery(launchId)).toState()
    val r = response
    when {
        r == null -> Loading() // no response yet
        r.exception != null -> ErrorMessage("Oh no... A network error happened: ${r.exception!!.message}")
        r.hasErrors() -> ErrorMessage("Oh no... A GraphQL error happened ${r.errors[0].message}.")
        else -> LaunchDetails(r.data!!, navigateToLogin)
    }
}

/**
 * A stateless composable that displays your data
 */
@Composable
private fun LaunchDetails(
        data: LaunchDetailsQuery.Data,
) {
  // Your UI code goes here
}

If you are working with paginated data, you can also add apollo-compose-paging-support to your dependencies:

// build.gradle.kts
dependencies {
  implementation("com.apollographql.apollo3:apollo-compose-paging-support")
}

This artifact contains a helper function to create androidx.pagin.Pager instances (androix documentation):

@OptIn(ApolloExperimental::class)
@Composable
fun LaunchList(onLaunchClick: (launchId: String) -> Unit) {
  val lazyPagingItems = rememberAndCollectPager<LaunchListQuery.Data, LaunchListQuery.Launch>(
          config = PagingConfig(pageSize = 10),
          appendCall = { response, loadSize ->
            if (response?.data?.launches?.hasMore == false) {
              // No more pages
              null
            } else {
              // Compute the next call from the current response
              apolloClient.query(
                      LaunchListQuery(
                              cursor = Optional.present(response?.data?.launches?.cursor),
                              pageSize = Optional.present(loadSize)
                      )
              )
            }
          },
          getItems = { response ->
            // Compute the items to be added to the page from the current response
            if (response.hasErrors()) {
              Result.failure(ApolloException(response.errors!![0].message))
            } else {
              Result.success(response.data!!.launches.launches.filterNotNull())
            }
          },
  )
  
  // Use your paging items:
  if (lazyPagingItems.loadState.refresh is LoadState.Loading) {
    Loading()
  } else {
    LazyColumn {
      items(lazyPagingItems) { launch ->
        // Your UI code goes here
      }
      item {
        when (val append = lazyPagingItems.loadState.append) {
          is LoadState.Error -> // Add error indicator here 
          LoadState.Loading -> // Add loading indicator here
        }
      }
    }
  }
}

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] Gradle plugin: run codegen after gradle sync

If you import a new project or run a Gradle sync, your GraphQL models are now automatically generated so that the IDE can find the symbols and your files do not show red underlines. This takes into account Gradle up-to-date checks and it should be pretty fast. If you want to opt-out, you can do so with generateSourcesDuringGradleSync.set(false):

apollo {
  // Enable automatic generation of models during Gradle sync (default)
  generateSourcesDuringGradleSync.set(true)

  // Or disable automatic generation of models to save on your Gradle sync times
  generateSourcesDuringGradleSync.set(false)

  service("api") {
    // Your  GraphQL configuration
  }
}

👷‍ All changes

  • Allow to add HTTP headers on top of ApolloClient ones (#4754)
  • Kotlin 1.8 (#4776)
  • Move cache creation outside the main thread (#4781)
  • Cache: ignore hardcoded @include(if: false) directives (#4795)
  • Add % to reserved characters to encode in URL (#4804)
  • First drop of experimental Compose support libraries (#4783)
  • Consider variable default values with @skip/@include/@defer (#4785)
  • Gradle plugin: run codegen after gradle sync (#4796)
  • Allow custom SqlDriver (#4806)
  • Multipart subscriptions (#4768, #4807, #4738)
  • GQLNode.print for type extensions (#4814)