Giter Club home page Giter Club logo

apollo-kotlin's Introduction

Apollo Kotlin

GitHub license Join the community Slack Discord CI Maven Central Gradle Plugin OSS Snapshots Revved up by Develocity

☑️ Apollo Clients User Survey
What do you like best about Apollo Kotlin? What needs to be improved? Please tell us by taking a one-minute survey. Your responses will help us understand Apollo Kotlin usage and allow us to serve you better.

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

Apollo Kotlin executes operations against a GraphQL server and returns results as operation-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 app uses.

Because generated types are operation-specific, you can only access data that you actually specify as part of an operation. If you don't ask for a particular field in an operation, 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 Kotlin (including multiplatform) and Java app.

Features

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

Multiplatform

Apollo Kotlin is a Kotlin Multiplatform project.

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

jvm Apple¹ js wasmJs 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
  • watchosArm32
  • watchosArm64
  • watchosSimulatorArm64
  • tvosArm64
  • tvosX64
  • tvosSimulatorArm64

Maintainers

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.

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 "4.0.0-beta.7"
}

Add the runtime dependency:

dependencies {
  implementation("com.apollographql.apollo3:apollo-runtime:4.0.0-beta.7")
}

Set the package name to use for the generated models:

apollo {
  service("service") {
    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/HeroQuery.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:

Requirements

Some platforms have specific runtime requirements:

  • JVM 8+
  • Android API level 21+ (apollo-http-cache and apollo-adapters require enabling core library desugaring on Android API levels < 26)
  • iOS 13+

At build time, it requires:

  • Gradle 8.0+
  • Kotlin 1.9+ for JVM projects
  • Kotlin 2.0+ for native, JS, and Wasm projects

Proguard / R8 configuration

As the code generated by Apollo Kotlin doesn't use any reflection, it can safely be optimized / obfuscated by Proguard or R8, so no particular exclusions need to be configured.

Android Studio / IntelliJ plugin

A plugin for Android Studio and IntelliJ is available to help you work with Apollo Kotlin, providing automatic code generation, integration with the GraphQL IntelliJ Plugin, navigation to GraphQL definitions, migration helpers, and more.

Installation instructions and more information can be found here.

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 "4.0.0-beta.7"
}

repositories {
  mavenCentral()
}

dependencies {
  implementation("com.apollographql.apollo3:apollo-runtime:4.0.0-beta.7")

  // Optional: if you want to use the normalized cache
  implementation("com.apollographql.apollo3:apollo-normalized-cache-sqlite:4.0.0-beta.7")
  // 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:4.0.0-beta.7")
}

Snapshots

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

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

// settings.gradle.kts
pluginManagement {
  repositories {
    maven {
      url = uri("https://s01.oss.sonatype.org/content/repositories/snapshots/")
    }
    gradlePluginPortal()
    mavenCentral()
    // other repositories...
  }
}

And then use the 4.0.0-beta.8-SNAPSHOT version for the plugin and libraries.

These snapshots are updated on each push to main.

Weekly snapshots for the Android Studio / IntelliJ plugin are also available.

Stability of different artifacts

Apollo Kotlin is very modular and publishes several artifacts.

  • Artifacts ending with -incubating are not finalized yet and subject to change any time.
  • Other artifacts observe Semantic Versioning.
    • No breaking change should be introduced in minor or patch releases except for symbols annotated with @ApolloExperimental that are subject to change at any time.
    • Deprecated symbols may be removed in the next major release. We strongly recommend removing deprecated usages before migrating to the next major version.

Contributing

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

Community integrations

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.

apollo-kotlin's People

Contributors

abernix avatar adammc331 avatar baconz avatar bignimbus avatar bod avatar brianplummer avatar designatednerd avatar digitalbuddha avatar dsteve595 avatar felipecsl avatar ghostbuster91 avatar github-actions[bot] avatar goooler avatar hwillson avatar jaredsburrows avatar jpvajda avatar kassim avatar martinbonnin avatar marwanad avatar meschreiber avatar oliveeyay avatar renovate-bot avatar renovate[bot] avatar rohandhruva avatar sav007 avatar stylianosgakis avatar tasomaniac avatar trevorblades avatar visheshvadhera avatar zacsweers avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

apollo-kotlin's Issues

[Code Generation] Add support of input types

In order to support mutation operation support input types is required.

Query as example :

mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
  createReview(episode: $ep, review: $review) {
    stars
    commentary
  }
}

IR json:

{
	"operations": [
		{
			"operationName": "CreateReviewForEpisode",
			"operationType": "mutation",
			"variables": [
				{
					"name": "ep",
					"type": "Episode!"
				},
				{
					"name": "review",
					"type": "ReviewInput!"
				}
			],
			"source": "mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {\n  createReview(episode: $ep, review: $review) {\n    stars\n    commentary\n  }\n}",
			"fields": [
				{
					"responseName": "createReview",
					"fieldName": "createReview",
					"type": "Review",
					"fields": [
						{
							"responseName": "stars",
							"fieldName": "stars",
							"type": "Int!"
						},
						{
							"responseName": "commentary",
							"fieldName": "commentary",
							"type": "String"
						}
					],
					"fragmentSpreads": [],
					"inlineFragments": []
				}
			],
			"fragmentsReferenced": []
		}
	],
	"fragments": [],
	"typesUsed": [
		{
			"kind": "EnumType",
			"name": "Episode",
			"description": "The episodes in the Star Wars trilogy",
			"values": [
				{
					"name": "NEWHOPE",
					"description": "Star Wars Episode IV: A New Hope, released in 1977."
				},
				{
					"name": "EMPIRE",
					"description": "Star Wars Episode V: The Empire Strikes Back, released in 1980."
				},
				{
					"name": "JEDI",
					"description": "Star Wars Episode VI: Return of the Jedi, released in 1983."
				}
			]
		},
		{
			"kind": "InputObjectType",
			"name": "ReviewInput",
			"description": "The input object sent when someone is creating a new review",
			"fields": [
				{
					"name": "stars",
					"description": "0-5 stars",
					"type": "Int!",
					"defaultValue": null
				},
				{
					"name": "commentary",
					"description": "Comment about the movie, optional",
					"type": "String",
					"defaultValue": null
				},
				{
					"name": "favoriteColor",
					"description": "Favorite color, optional",
					"type": "ColorInput",
					"defaultValue": null
				}
			]
		},
		{
			"kind": "InputObjectType",
			"name": "ColorInput",
			"description": "The input object sent when passing in a color",
			"fields": [
				{
					"name": "red",
					"description": "",
					"type": "Int!",
					"defaultValue": null
				},
				{
					"name": "green",
					"description": "",
					"type": "Int!",
					"defaultValue": null
				},
				{
					"name": "blue",
					"description": "",
					"type": "Int!",
					"defaultValue": null
				}
			]
		}
	]
}

[Code Generation] Generate query wrapper class around query text source and variables

Create generic GraphQLQuery interface like iOS does
Generate query class implemtentation for each query by implementing GraphQLQuery.
Generated query class implemtentations should allow set arguments.

See https://github.com/apollostack/apollo-android/blob/design-doc/DESIGN.md#query-classes
Swift examples can be found here: https://github.com/apollostack/apollo-ios/blob/master/Tests/ApolloTests/StarWars/API.swift

[Code Generation] Need details about external types referenced in typesUsed array

From Slack discussion:

felipecsl [12:21 PM]
@martijnwalraven I was looking at the HeroAppearsIn query and the generated IR references the Episode type in the typesUsed array, however its definition can’t be found anywhere in the data. Also I checked the Swift code generated for that query and noticed that it does include a public enum Episode. Sounds like we’re gonna have to add the definition of any external types to the IR so we can generate code based solely on the IR. It sounds like the Swift generator is retrieving that data from somewhere else

[Code Generation] Add Retrofit service interface generation support

We can generate Retrofit service with all defined query endpoints to follow with this pattern:

public interface ApiService {
    @POST
    Call<Response<%QUERY_TYPE%.Data>> %QUERY_NAME%(@Body GraphQlOperationRequest<%QUERY_TYPE%.Variables> query);
...
  }

This generated service to be used with Retrofit client:

ApiService apiService = retrofit.create(ApiService.class);

With such service declaration Retrofit client must be configured with base url pointed to graphql endpoint.

 Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http:// ..... /graphql/")

[Runtime] Mapping json response to generated data models

Query data model generated by apollo android plugin is represented by interfaces. In order to deserialize query response (json) and map it to the data model, apollo service requires to know about the user defined instance classes of that data model. Generated interface declares only accessor api calls to fields (no setters and of course no fields).

Questions:

  1. As we discussed before, custom retrofit converter will be implemented in order to support deserializing response. How this converter will get knowledge about setters / fields of user defined data model implementations to be able to map json response fields?

  2. How converter is going to instantiate the user defined instances of the model interfaces?

One approach that we considered user uses AutoValue lib to generate instances of data model interfaces. Here is an example of generated model interface:

public interface Data extends Query.Data {
     Hero hero();

    interface Hero {
       String name();

       AsHuman asHuman();

      interface AsHuman {
         String name();

         List<Friend> friends();

         Float height();

        interface Friend {
           String name();

           List<Episode> appearsIn();
        }
      }
...

Then from user to use AutoValue requires to define abstract classes / interfaces that extend all interfaces: Data, Data.Hero, Data.Hero.AsHuman, Data.Hero.AsHuman.Friend etc. with @AutoValue annotation that seems too overwhelming . Even more AutoValue generates immutable value objects that initialize fields inside constructor. So retrofit converter has to parse response json and pass parsed field values as parameters to this constructor.
But converter doesn't know anything about user defined instance classes and especially about how to construct them, so it will require some sort of factory the same approach as SQLDelight implements.

All this complication brings to question, maybe we have to change our code generation to have model be classes with fields, rather then interfaces.

@felipecsl @martijnwalraven @marwanad

[Runtime] Create simple Apollo object

It should have a simple builder interface that takes at least a retrofit object and is able to fire GraphQL requests using the generated query interfaces and optionally arguments.

[Code Generation] Handle Directives on inlineFragments

Example query:

query inlineFragmentNoType($expandedInfo: Boolean) {
  user(handle: "zuck") {
    id
    name
    ... on User @include(if: $expandedInfo) {
      firstName
      lastName
      birthday
    }
  }
}

For fragment spreads, we can augment the fragment spread in the IR with an isConditional field.

Add a schema download task

apollo-codegen supports downloading the schema by sending an introspection query to the server.
It would be nice to have a task that utilizes apollo-codegen download

[Refactoring] Remove code duplication from GraphQLCompilerTest

All Junit tests in GraphQLCompilerTest follow the same pattern:

  1. check actual generated file with expected
  2. compile

A lot of code duplication. We can do better, define only test fixtures (probably map of actual / expected file paths) and run tests against them

[Code Generation] Add support for directives

Add support for @skip and @include directives

query HeroNameInclusionDirective {
     hero {
          name @include(if: someCondition)
        }
}

There would be an isConditional field in the IR and handling those should be somewhat similar to handling nullability.

Generated classes are created under generatedIR package

The gradle plugin doesn't seem to be respecting the original package name of each graphql file and just adding them all into the generatedIR package (eg.: build/generated/source/apollo/generatedIR/DroidDetails.java)

The generated package name should match the original file path.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.