Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

📚 Documentation updates for next version #5866

Merged
merged 6 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
38 changes: 38 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,44 @@
Change Log
==========

# Version 4.0.0-beta.7

_2024-06-05_

## K2

#5931: This version is built with K2. You will need Kotlin 1.9+ on the JVM to build it and Kotlin 2.0 for other platforms.

## ApolloCompilerPluginProvider

#5865: `ApolloCompilerPluginProvider` is introduced to allow passing arguments to compiler plugins. See the [compiler plugins documentation](https://go.apollo.dev/ak-compiler-plugins) for more details.

## 👷‍ All changes
[testing] Use com.apollographql.mockserver.MockServer (#5939)
[testing] Simplify our implementation of runTest (#5935)
[testing] Prepare apollo-testing-support to new MockServer (#5934)
[runtime] Remove multidex library (#5930)
[all] Bump languageVersion/apiVersion to Kotlin 2.0 (#5931)
[codegen] fix mapping of the builtin Float type (#5928)
[IJ Plugin] Add inspection to warn about the presence of a GraphQL config file (#5908)
[codegen] Add a null-check to java enum safeValueOf (#5904)
[gradle-plugin] Remove eager configuration (#5923)
[gradle-plugin] sort input files (#5919)
[IJ Plugin] Suppress GraphQLDuplicateDirective for certain directives (#5910)
[adapters] Add KtorHttpUrlAdapter (#5915)
[IJ Plugin] Add a "new UI" compatible icon (#5906)
[IJ Plugin] Operation and fragment definition rename (#5912)
[IJ Plugin] Add @link directives to extra.graphqls during v3->v4 migration (#5909)
[IJ Plugin] Remove GraphQL IJ plugin issue workaround (#5907)
[cache] Pagination: use "field key" instead of "field name" (#5898)
[IJ Plugin] Improve the presentation of GraphQL elements when navigating to them (#5900)
[IJ Plugin] Include subfolders when contributing GraphQL config (#5871)
[runtime] Remove existing interceptors from ApolloClient.Builder before adding new ones (#5858)
[codegen] Add ApolloCompilerPluginProvider (#5865)
[runtime] Clear current ApolloStore related interceptors when calling `.store()` on builder (#5857)
[cache] Call through to loadRecords from the MemoryCache to the SQL one (#5848)
[runtime] deprecate operationIdGenerator (#5850)

# Version 3.8.4

_2024-04-29_
Expand Down
57 changes: 38 additions & 19 deletions docs/source/advanced/compiler-plugins.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ Apollo compiler plugins allow to:
* Transform the JavaPoet/KotlinPoet models.
* Transform the Apollo IR.

# Implementing a compiler plugin
## Implementing a compiler plugin

In this example we will implement a plugin that uses custom [persisted queries](../advanced/persisted-queries) ids registered on your backend.

The Apollo compiler use the [ServiceLoader API](https://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html) to load plugins at runtime. Plugins need to be implemented in a separate module that is added to the classpath.

To start, create a new Gradle module and add `apollo-compiler` as a dependency to the module `build.gradle[.kts]` file. In this example, we'll use `apollo-compiler-plugin` for the module name:
To start, create a new Gradle module and add `apollo-compiler` as a dependency to the module `build.gradle[.kts]` file. In this example, we'll use `apollo-compiler-plugin` as module name:

```kotlin
// apollo-compiler-plugin/build.gradle.kts
Expand Down Expand Up @@ -56,18 +56,28 @@ class MyPlugin: ApolloCompilerPlugin {
}
```

Make your plugin discoverable by [ServiceLoader](https://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html) using a resource in `src/main/resources/META-INF/services/com.apollographql.apollo3.compiler.ApolloCompilerPlugin`. This file contains the fully qualified name of your plugin:
Next, create an `ApolloCompilerPluginProvider`. This is the entry point of compiler plugins. It is loaded using the [ServiceLoader](https://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html) API.

```kotlin
class MyPluginProvider: ApolloCompilerPluginProvider {
override fun create(environment: ApolloCompilerPluginEnvironment): ApolloCompilerPlugin {
return MyPlugin()
}
}
```
mypackage.MyPlugin

Make your plugin discoverable by [ServiceLoader](https://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html) by adding a resource in `src/main/resources/META-INF/services/com.apollographql.apollo3.compiler.ApolloCompilerPluginProvider`. This file contains the fully qualified name of your plugin:

```
mypackage.MyPluginProvider
```

<Note>

The name of the resource file is important. It must be `com.apollographql.apollo3.compiler.ApolloCompilerPlugin` and be in the `META-INF/services` folder. This is how `ServiceLoader` looks up plugins at runtime.
The name of the resource file is important. It must be `com.apollographql.apollo3.compiler.ApolloCompilerPluginProvider` and be in the `META-INF/services` folder. This is how `ServiceLoader` looks up plugins at runtime.
</Note>

# Adding a plugin to the Apollo compiler classpath
## Adding a plugin to the Apollo compiler classpath

Use the `Service.plugin()` Gradle method to add the plugin to the Apollo compiler classpath:

Expand All @@ -90,36 +100,45 @@ apollo {

The plugin code will now be invoked the next time the compiler is invoked.

# Passing arguments to your Apollo compiler plugin
## Passing arguments to your Apollo compiler plugin

Because the compiler plugin runs in an isolated classpath, you can't use classes or data from your main build logic classpath.

In order to pass build-time arguments to your Apollo compiler plugin, you can use code generation and tools like [gradle-buildconfig-plugin](https://github.com/gmazzo/gradle-buildconfig-plugin):
In order to pass build-time arguments to your Apollo compiler plugin, use the `argument()` function:

```kotlin
// my-plugin/build.gradle.kts
plugins {
id("com.github.gmazzo.buildconfig")
apollo {
service("service") {
packageName.set("com.example")

// Add your plugin to the Apollo compiler classpath
plugin(project(":apollo-compiler-plugin")) {
argument("token", token) // highlight-line
}
}
}
```

buildConfig {
useKotlinOutput()
packageName("com.example.myplugin")
The arguments are available in `ApolloCompilerPluginEnvironment.arguments`:

buildConfigField("arg1", arg1Value)
buildConfigField("arg2", arg2Value)
// etc...
```kotlin
class MyPluginProvider: ApolloCompilerPluginProvider {
override fun create(environment: ApolloCompilerPluginEnvironment): ApolloCompilerPlugin {
return MyPlugin(environment.arguments.get("token") as String)
}
}
```

# Limitations
Arguments must be serializable and be instances of classes accessible from the bootstrap classloader. In practice, built-in types and collections are supported.

## Limitations

Because codegen is run in a separate classloader when using compiler plugins, it's not possible to use `packageNameGenerator`, `operationIdGenerator` or `operationOutputGenerator` at the same time as compiler plugins. If you want to use them, you'll have to:

* use `ApolloCompilerPlugin.layout()` instead of `packageNameGenerator`
* use `ApolloCompilerPlugin.operationIds()` instead of `operationIdGenerator` and `operationOutputGenerator`

# Other references
## Other references

For other plugin APIs like layout, IR, JavaPoet and KotlinPoet transforms, check out the [ApolloCompilerPlugin API docs](https://www.apollographql.com/docs/kotlin/kdoc/apollo-compiler/com.apollographql.apollo3.compiler/-apollocompilerplugin/index.html)

Expand Down
98 changes: 85 additions & 13 deletions docs/source/migration/4.0.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ Apollo Kotlin 4.0 focuses on tooling, stability and fixing some API regrets that

Because most of the common APIs stayed the same, we [kept the package name unchanged](https://github.com/apollographql/apollo-kotlin/issues/4710). Apollo Kotlin 4.0 removes some deprecated symbols. We strongly recommend removing deprecated usages before migrating to 4.0.

If you are using a lib that depends on Apollo Kotlin transitively, you need it to update to 4.x before you can update your own app to 4.0.
If you are using a library that depends on Apollo Kotlin transitively, you need it to update to 4.x before you can update your own application to 4.0.

## Automatic migration using the Android Studio plugin

Apollo Kotlin 4 ships with a companion [Android Studio plugin that automates most of the migration](https://www.apollographql.com/docs/kotlin/v4/testing/android-studio-plugin#migration-helpers).
Apollo Kotlin 4 ships with a companion [Android Studio plugin](../testing/android-studio-plugin#migration-helpers) that automates most of the migration.

It automates most of the API replacements but cannot deal with behaviour changes like error handling.
It automates most of the API changes but cannot deal with behaviour changes like error handling.

We recommend using the plugin to automate the repetitive tasks but still go through this document for the details.

Expand Down Expand Up @@ -112,12 +112,12 @@ apolloClient.query(query).watch().filter { it.exception == null }

### ApolloCompositeException is not thrown anymore

When using the cache, Apollo Kotlin 3.x threw `ApolloCompositeException` if no response could be found. For an example, a `CacheFirst` fetch policy would throw `ApolloCompositeException(cacheMissException, apolloNetworkException` if both cache and network failed.
When using the cache, Apollo Kotlin 3.x threw `ApolloCompositeException` if no response could be found. For an example, a `CacheFirst` fetch policy would throw `ApolloCompositeException(cacheMissException, apolloNetworkException)` if both cache and network failed.

In those cases, Apollo Kotlin 4.0 throws the first exception and adds the second as a suppressed exception:

```kotlin
// Replace
// Replace
if (exception is ApolloCompositeException) {
val cacheMissException = exception.first
val networkException = exception.second
Expand Down Expand Up @@ -152,7 +152,7 @@ Because of the number of different options in 3.x and the complexity of error ha

## Other Apollo Runtime changes

### HTTP headers
### Non standard HTTP headers are not sent by default

`X-APOLLO-OPERATION-NAME` and `X-APOLLO-OPERATION-ID` are non-standard headers and are not sent by default anymore. If you used them for logging purposes or if you are using Apollo Server [CSRF prevention](https://www.apollographql.com/docs/apollo-server/security/cors/#preventing-cross-site-request-forgery-csrf), you can add them back using an [ApolloInterceptor](https://www.apollographql.com/docs/kotlin/kdoc/apollo-runtime/com.apollographql.apollo3.interceptor/-apollo-interceptor/index.html?query=interface%20ApolloInterceptor):

Expand All @@ -171,6 +171,8 @@ Because of the number of different options in 3.x and the complexity of error ha
.build()
```

### `ApolloCall.Builder.httpHeaders` is additive

In v3, if HTTP headers were set on an `ApolloCall`, they would replace the ones set on `ApolloClient`. In v4 they are added instead by default. To replace them, call `ApolloCall.Builder.ignoreApolloClientHttpHeaders(true)`.

```kotlin
Expand Down Expand Up @@ -334,6 +336,7 @@ If you are using `packageNamesFromFilePaths` and `schemaFile`, you'll need to us
Apollo Kotlin 3 was using the operation root directories to compute the schema normalized path which could be wrong in some edge cases. Using fileTree ensures the normalized path is consistent.
</Note>

<<<<<<< HEAD
### Migrating to ApolloCompilerPlugin

4.0 introduces `ApolloCompilerPlugin` as a way to customize code generation. `ApolloCompilerPlugin` are loaded using the [ServiceLoader](https://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html) API and run in a separate classloader from your Gradle build. As a result, using `Service.operationIdGenerator`/`Service.operationOutputGenerator` together with `ApolloCompilerPlugin` is not possible.
Expand Down Expand Up @@ -371,11 +374,19 @@ class MyPlugin: ApolloCompilerPlugin {
```

### Misc
=======
### Publishing is no longer configured automatically
>>>>>>> 7f97423f7b (Migration guide tweaks (#5937))

In Apollo Kotlin 3, maven publishing was automatically configured. In Apollo Kotlin 4, this is no longer the case, and you need to configure the publishing tasks yourself.

* Publishing is no longer configured automatically.
* Because Apollo Kotlin now supports different operation manifest formats, `operationOutput.json` has moved from `"build/generated/operationOutput/apollo/$service/operationOutput.json"` to `"build/generated/manifest/apollo/$service/operationOutput.json"`
* useSchemaPackageNameForFragments is removed
### Operation manifest file location

Since Apollo Kotlin now supports [different operation manifest formats](../advanced/persisted-queries), the `operationOutput.json` file will be generated in `"build/generated/manifest/apollo/$service/operationOutput.json"` instead of `"build/generated/operationOutput/apollo/$service/operationOutput.json"`.

### `useSchemaPackageNameForFragments` is removed

This was provided for compatibility with 2.x and is now removed. If you need specific package names for fragments, you can use a [compiler plugin](../advanced/compiler-plugins) and `ApolloCompilerPlugin.layout()` instead.

## Apollo Compiler

Expand Down Expand Up @@ -442,7 +453,11 @@ data.hero.name
*/
data.hero.onCharacter?.name
```
> The [Android Studio plugin](https://www.apollographql.com/docs/kotlin/v4/testing/android-studio-plugin#migration-helpers) provides a compat to operationBased migration tool which automates a lot of these changes.

<Note>
The [Android Studio plugin](../testing/android-studio-plugin#migration-helpers) provides a `compat` to `operationBased` migration tool which automates a lot of these changes.
</Note>

### Enum class names now have their first letter capitalized

For consistency with other types, GraphQL enums are now capitalized in Kotlin. You can restore the previous behaviour using `@targetName`:
Expand All @@ -457,7 +472,7 @@ enum someEnum @targetName(name: "someEnum"){

### `__Schema` is in the `schema` subpackage

If using the `generateSchema` option, and to avoid a name clash with the introspection type of the same name, the `__Schema` type is now generated in a `schema` subpackage (instead of `type`) when using the `generateSchema` option:
When using the `generateSchema` option, to avoid a name clash with the introspection type of the same name, the `__Schema` type is now generated in a `schema` subpackage (instead of `type`):

```kotlin
// Replace
Expand Down Expand Up @@ -498,12 +513,26 @@ query HeroName {

Those queries now required to have a matching directive definition in the schema. If the directive is a server directive, and you downloaded your schema using introspection, the directive definition should be present.

In some cases, for client directives and/or if you did n ot use introspection, the directive definition might be missing. For those cases, you can add it explicitely in a `extra.graphqls` file:
In some cases, for client directives and/or if you did not use introspection, the directive definition might be missing. For those cases, you can add it explicitely in a `extra.graphqls` file:

```graphql
directive @required on FIELD
```

### Sealed class `UNKNOWN__` constructors are private

When generating enums as sealed classes with the `sealedClassesForEnumsMatching` option, the `UNKNOWN__` constructor is now generated as private, to prevent its accidental usage.

It is recommended to update your schema instead of instantiating an `UNKNOWN__` value, but if you need to, use the `safeValueOf` method instead:

```kotlin
// Replace
val myEnum = MyEnum.UNKNOWN__("foo")

// With
val myEnum = MyEnum.safeValueOf("foo")
```

## Cache

### ApolloStore
Expand All @@ -517,6 +546,22 @@ In Apollo Kotlin 4.0 this is still the case but the functions are no longer mark

The normalized cache must be configured before the auto persisted queries, configuring it after will now fail (see https://github.com/apollographql/apollo-kotlin/pull/4709).

```kotlin
// Replace
val apolloClient = ApolloClient.Builder()
.serverUrl(...)
.autoPersistedQueries(...)
.normalizedCache(...)
.build()

// With
val apolloClient = ApolloClient.Builder()
.serverUrl(...)
.normalizedCache(...)
.autoPersistedQueries(...)
.build()
```

## apollo-ast

The AST classes (`GQLNode` and subclasses) as well as `Introspection` classes are not data classes anymore (see https://github.com/apollographql/apollo-kotlin/pull/4704/). The class hierarchy has been tweaked so that `GQLNamed`, `GQLDescribed` and `GQLHasDirectives` are more consistently inherited from.
Expand All @@ -525,7 +570,7 @@ The AST classes (`GQLNode` and subclasses) as well as `Introspection` classes ar

`GQLInlineFragment.typeCondition` is now nullable to account for inline fragments who inherit their type condition.

`SourceLocation.position` is renamed `SourceLocation.column` and is now 1-indexed. `GQLNode.sourceLocation` is now nullable to account for the cases where the nodes are constructed programmatically.
`SourceLocation.position` is renamed to `SourceLocation.column` and is now 1-indexed. `GQLNode.sourceLocation` is now nullable to account for the cases where the nodes are constructed programmatically.

It is not possible to create a `Schema` from a File or String directly anymore. Instead, create a `GQLDocument` first and convert it to a schema with `toSchema()`.

Expand Down Expand Up @@ -563,6 +608,33 @@ apolloClient.query().rxSingle()
apolloClient.query().toFlow().asFlowable().firstOrError()
```

## New Maven coordinates for some artifacts

Over the years, a lot of support functionality was added alongside `apollo-runtime`. While useful, most of this functionality doesn't share the same level of stability and bundling the release does not make much sense.

Moving forward, `apollo-mockserver` is released separately.

Replace maven coordinates:

```kotlin
dependencies {
// Replace
testImplementation("com.apollographql.apollo3:apollo-mockserver:$apolloVersion")

// With
testImplementation("com.apollographql.mockserver:apollo-mockserver:$mockServerVersion")
}
```

And the package names:

```kotlin
// Replace
import com.apollographql.apollo3.mockserver

// With
import com.apollographql.mockserver
```

## Example of a migration

Expand Down