SlideShare a Scribd company logo
1 of 71
Download to read offline
Query DroidConNYC{ slide(id: "1")
{
Title
Authors
Company
}
}
{
Title: "Intro to GraphQL on Android",
Authors: ["Brian Plummer","Mike Nakhimovich"],
Company: "The New York Times"
}
We work at The
New York Times
We do a lot of data
loading
Recently, our team moved from
using RESTful APIs to GraphQL for
our data loading architecture
What’s GraphQL?
• A query language for APIs and a runtime for fulfilling those
queries with your existing data
• Alternative to RESTful API
• Client driven - get only data you need
• Works on iOS, Android, Web
GraphQL was created by Facebook as a new
standard for server/client data transfer
• Give front end developers an efficient way to ask for minimal
data
• Give server-side developers a robust way to get their data out to
their users
GraphQL is As Easy as 1-2-3
• Describe your data
• Ask for what you want
• Get predictable results
Describe Your Data in a Schema
type Character {
name: String!
appearsIn: [Episode]!
}
Describe Your Data in a Schema
type Character {
name: String!
appearsIn: [Episode]!
}
Character is a GraphQL Object Type, meaning it's a type with some
fields. Most of the types in your schema will be object types.
Describe Your Data in a Schema
type Character {
name: String!
appearsIn: [Episode]!
}
name and appearsIn are fields on the Character type. That means
that name and appearsIn are the only fields that can appear in any
part of a GraphQL query that operates on the Character type.
Describe Your Data in a Schema
type Character {
name: String!
appearsIn: [Episode]!
}
String is one of the built-in scalar types. These are types that
resolve to a single scalar object and can't have sub-selections in
the query.
GraphQL Example Schema
type Character {
name: String!
appearsIn: [Episode]!
}
String! means that the field is non-nullable, meaning that the
GraphQL service promises to always give you a value when you
query this field.
GraphQL Example Schema
type Character {
name: String!
appearsIn: [Episode]!
}
[Episode]! represents an array of Episode objects. Since it is also
non-nullable, you can always expect an array (with zero or more
items) when you query the appearsIn field.
Ask for what you need
get predictable results
Combine Resources into
One Request
{
hero {
name
# Queries can have comments
friends {
name
}
}
}
Combine Resources into
One Request
{
hero {
name
# Queries can have comments
friends {
name
}
}
}
Reuse Fields in a Fragment
{
leftColumn: hero(episode: EMPIRE) {
...comparisonFields
}
rightColumn: hero(episode: JEDI) {
...comparisonFields
}
}
fragment comparisonFields on Character {
name
appearsIn
}
Reuse Fields in a Fragment
{
leftColumn: hero(episode: EMPIRE) {
...comparisonFields
}
rightColumn: hero(episode: JEDI) {
...comparisonFields
}
}
fragment comparisonFields on Character {
name
appearsIn
}
Example:
Loading Data from
Github Using REST
vs GraphQL
On any platform, data loading consists of these steps:
1. Model Data
2. Network
3. Transform
4. Persist
How does REST look on Android?
...It Looks Like a lot of Dependencies
Data Modeling Networking Storage Transform
Immutables OKhttp Store Gson
Curl Retrofit SqlDelight RxJava
Yes, those are all needed !
Start with Inspection
curl -i "https://api.github.com/repos/vmg/redcarpet/issues?state=closed"
Model Your Data
interface Issue {
User user();
String url();
interface User {
long id();
String name();
}
}
Error prone even with code generation
Data Modeling with Immutables
@Value.Immutable
interface Issue {
User user();
String url();
@Value.Immutable
interface User {
long id();
String name();
}
}
Error Prone even with Code Generation
Data Parsing with Gson
@Gson.TypeAdapters
@Value.Immutable
interface Issue {
User user();
String url();
@Value.Immutable
interface User {
long id();
String name();
}
}
Networking
open fun provideRetrofit(gson: Gson, okHttpClient: OkHttpClient): GithubApi {
return Retrofit.Builder()
.client(okHttpClient)
.baseUrl(BuildConfig.BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build()
.create(GithubApi::class.java!!)}
Storage
CREATE TABLE issue (
_id LONG PRIMARY KEY AUTOINCREMENT,
id LONG NOT NULL,
url STRING,
title STRING,
comments INT NOT NULL
}
Storage
public abstract class Issue implements IssueModel {
public static final Mapper<Issue> MAPPER =
new Mapper<>((Mapper.Creator<Issue>)
ImmutableIssue::of);
public static final class Marshal extends IssueMarshal {
}
}
Storage
long insertIssue(Issue issue) {
if (recordExists(Issue.TABLE_NAME, Issue.ID, String.valueOf(issue.id()))) {
return 0;
}
return db.insert(Issue.TABLE_NAME, new Issue.Marshal()
.url(issue.url())
.id(issue.id()));
}
Storage - Memory
StoreBuilder.parsedWithKey<GitHubOrgId, BufferedSource, Issues>()
.fetcher(fetcher)
.persister(persister)
.parser(parser)
.memoryPolicy(MemoryPolicy
.builder()
.setMemorySize(11L)
.setExpireAfterWrite(TimeUnit.HOURS.toSeconds(24))
.setExpireAfterTimeUnit(TimeUnit.SECONDS)
.build())
.networkBeforeStale()
.open()
That's a Good Architecture
It's also not something we can
expect a beginner to know
REST Feels Like Legacy Tech
Well-established and with great tools, but
cumbersome to work with
Thanks to Facebook, there's a new kid on the block
GraphQL
Now, Let's See GraphQL on Android
We can't since Facebook didn't open
source an Android Client, Thanks
for your time and goodnight !
Just Kidding, Community to the Rescue!
Introducing Apollo-Android GraphQL
Apollo Android was developed by Shopify, New York Times, &
AirBnb as an Open Source GraphQL solution.
Apollo-Android
• Built by Android devs for Android devs
• A strongly-typed, caching GraphQL client for Android
• Rich support for types and type mappings
• Code generation for the messy parts
• Query validation at compilation
Meets Facebook's GraphQL Spec
• Works with any GraphQL Query
• Fragments
• Union Types
• Nullability
• Deprecation
Apollo Reduces Setup to Work with a Backend
Data Modeling Networking Storage Transform
Github Explorer OKhttp Apollo RxJava
Apollo Apollo Apollo Apollo
You Ain't Gonna Need It
Retrofit | Immutables| Gson | Guava | SqlDelight/Brite | Store | Curl
| JsonViewer.hu
Apollo-Android Has 2 Main Parts
• Gradle Plugin Apollo code generation plugin
• Runtime Apollo client for executing operations
Using Apollo-Android
like a boss
Add Apollo Dependencies
build.gradle:
dependencies {
classpath 'com.apollographql.apollo:gradle-plugin:0.4.1'
}
app/build.gradle:
apply plugin: 'com.apollographql.android'
.....
//optional RxSupport
compile 'com.apollographql.apollo:apollo-rx-support:0.4.1'
Create a Standard GraphQL Query
Queries have params and define shape of response
organization(login:”nyTimes”){
repositories(first:6) {
Name
}
}
Leave Your CURL at Home
Most GraphQL Servers have a GUI (GraphiQL)
https://developer.github.com/v4/explorer/
GraphiQL: Explore Schema and Build Queries
• Shape of Response
• Nullability Rules
• Enum values
• Types
GraphiQL is easy!
Add Schema & RepoQuery.graphql to project & compile
Apollo Writes Code So You Don't Have To
private fun CodeGenerationIR.writeJavaFiles(context: CodeGenerationContext, outputDir: File,
outputPackageName: String?) {
fragments.forEach {
val typeSpec = it.toTypeSpec(context.copy())
JavaFile.builder(context.fragmentsPackage, typeSpec).build().writeTo(outputDir)
}
typesUsed.supportedTypeDeclarations().forEach {
val typeSpec = it.toTypeSpec(context.copy())
JavaFile.builder(context.typesPackage, typeSpec).build().writeTo(outputDir)
}
if (context.customTypeMap.isNotEmpty()) {
val typeSpec = CustomEnumTypeSpecBuilder(context.copy()).build()
JavaFile.builder(context.typesPackage, typeSpec).build().writeTo(outputDir)
}
operations.map { OperationTypeSpecBuilder(it, fragments, context.useSemanticNaming) }
.forEach {
val packageName = outputPackageName ?: it.operation.filePath.formatPackageName()
val typeSpec = it.toTypeSpec(context.copy())
JavaFile.builder(packageName, typeSpec).build().writeTo(outputDir)
}
}
Actually Ivan(sav007) Does (He's Awesome)
Builder - For Creating Your Request Instance
///api
val query = RepoQuery.builder.name("nytimes").build()
//Generated Code
public static final class Builder {
private @Nonnull String name;
Builder() {
}
public Builder name(@Nonnull String name) {
this.name = name;
return this;
}
public RepoQuery build() {
if (name == null) throw new IllegalStateException("name can't be null");
return new RepoQuery(name);
}
}
Notice How Our Request Param name is Validated
///api
val query = RepoQuery.builder.name("nytimes").build()
//Generated Code
public static final class Builder {
private @Nonnull String name;
Builder() {
}
public Builder name(@Nonnull String name) {
this.name = name;
return this;
}
public RepoQuery build() {
if (name == null) throw new IllegalStateException("name can't be null");
return new RepoQuery(name);
}
}
Response Models
public static class Repositories {
final @Nonnull String __typename;
final int totalCount;
final @Nullable List<Edge> edges;
private volatile String $toString;
private volatile int $hashCode;
private volatile boolean $hashCodeMemoized;
public @Nonnull String __typename() { return this.__typename; }
//Identifies the total count of items in the connection.
public int totalCount() {return this.totalCount;}
//A list of edges.
public @Nullable List<Edge> edges() {return this.edges;}
@Override
public String toString() {...}
@Override
public boolean equals(Object o) { ... }
@Override
public int hashCode() {...}
Mapper - Reflection-Free Parser
public static final class Mapper implements ResponseFieldMapper<Repositories> {
final Edge.Mapper edgeFieldMapper = new Edge.Mapper();
@Override
public Repositories map(ResponseReader reader) {
final String __typename = reader.readString($responseFields[0]);
final int totalCount = reader.readInt($responseFields[1]);
final List<Edge> edges = reader.readList($responseFields[2], new ResponseReader.ListReader<Edge>() {
@Override
public Edge read(ResponseReader.ListItemReader reader) {
return reader.readObject(new ResponseReader.ObjectReader<Edge>() {
@Override
public Edge read(ResponseReader reader) {
return edgeFieldMapper.map(reader);
}
});
}
});
return new Repositories(__typename, totalCount, edges);
}}
Can parse 20MB Response w/o OOM
Querying Github's API
With Apollo Client
Building an Apollo Client
ApolloClient.builder()
.serverUrl("https://api.github.com/graphql)
.okHttpClient(okhttp)
.build();
Querying a Backend
query = RepoQuery.builder().name("nytimes").build()
Querying a Backend
query = RepoQuery.builder().name("nytimes").build()
ApolloQueryCall githubCall = apolloClient.query(query);
Querying a Backend
query = RepoQuery.builder().name("nytimes").build()
ApolloQueryCall githubCall = apolloClient.query(query);
githubCall.enqueue(new ApolloCall.Callback<>() {
@Override
public void onResponse(@Nonnull Response<> response) {
handleResponse(response);
}
@Override
public void onFailure(@Nonnull ApolloException e) {
handleFailure(e);
}
});
Apollo also Handles Storage
Storage with Apollo is done through Caches
• HTTP
• Normalized
HTTP Caching
• Similar to OKHTTP Cache (LRU)
• Streams response to cache same time as parsing
• Can Set Max Cache Size
• Useful for background updating to prefill cache
• Prefetching
apolloClient.prefetch(new RepoQuery("nytimes"));
HTTP Caching - as well as you can do in REST
Apollo Introduces a Normalized Cache
Apollo Store
Apollo Store
• Allows multiple queries to share same cached values
• Great for things like master/detail
• Caching is done post-parsing
• Each field is cached individually
• Apollo ships with both an in memory and a disk implementation
of an Apollo Store
• You can even use both at same time
How Does Apollo Store Work?
• Each Object in Response will have its own record with ID
• All Scalars/Members will be merged together as fields
• When we are reading from Apollo, it will seamlessly read from
Apollo Store or network
Setup Bi-Level Caching with Apollo Store
//Create DB
ApolloSqlHelper apolloSqlHelper = ApolloSqlHelper.create(context, "db_name");
//Create NormalizedCacheFactory
NormalizedCacheFactory normalizedCacheFactory = new LruNormalizedCacheFactory(EvictionPolicy.NO_EVICTION)
.chain(new SqlNormalizedCacheFactory(apolloSqlHelper));
Create a Cache Key Resolver
//Create the cache key resolver
CacheKeyResolver cacheKeyResolver = new CacheKeyResolver() {
@Nonnull @Override
public CacheKey fromFieldRecordSet(@Nonnull ResponseField field, @Nonnull Map<String, Object> recordSet) {
String typeName = (String) recordSet.get("__typename");
if (recordSet.containsKey("id")) {
String typeNameAndIDKey = recordSet.get("__typename") + "." + recordSet.get("id");
return CacheKey.from(typeNameAndIDKey);
}
return CacheKey.NO_KEY;
}
@Nonnull @Override
public CacheKey fromFieldArguments(@Nonnull ResponseField field, @Nonnull Operation.Variables variables) {
return CacheKey.NO_KEY;
}
};
Init Apollo Client With a Cache
//Build the Apollo Client
ApolloClient apolloClient = ApolloClient.builder()
.serverUrl("/")
.normalizedCache(cacheFactory, resolver)
.okHttpClient(okHttpClient)
.build();
Don't Like Our Cache? BYO Cache
public abstract class NormalizedCache {
@Nullable public abstract Record loadRecord(@Nonnull String key, @Nonnull CacheHeaders cacheHeaders)
@Nonnull public Collection<Record> loadRecords(@Nonnull Collection<String> keys, @Nonnull CacheHeaders cacheHeaders)
@Nonnull public abstract Set<String> merge(@Nonnull Record record, @Nonnull CacheHeaders cacheHeaders)
public abstract void clearAll()
public abstract boolean remove(@Nonnull CacheKey cacheKey)
Apollo Is Reactive
QueryWatcher is a listener for changes to any fields in a
query.
• When a dependent field changes in the Apollo Store,
QueryWatcher will re-emit the response.
• QueryWatcher ~ endless subscription to a particular query.
Insert Example of a query watcher
Bonus: Includes RxJava Bindings
RxApollo.from(apolloClient.query(RepoQuery.builder().name("nytimes").build()))
.map(dataResponse -> dataResponse
.data()
.organization()
.repositories())
.subscribe(view::showRepositories, view::showError)
RxApollo response can be transformed into
LiveData
Version 1.0 ships soon!
• 380 commits
• 1000s of tests
• 18 contributors including devs from Shopify, Airbnb, NY Times
• Come join us at https://github.com/apollographql/apollo-
android

More Related Content

What's hot

Reactive Programming with JavaScript
Reactive Programming with JavaScriptReactive Programming with JavaScript
Reactive Programming with JavaScriptCodemotion
 
Why is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosWhy is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosDivante
 
Oleksandr Tolstykh
Oleksandr TolstykhOleksandr Tolstykh
Oleksandr TolstykhCodeFest
 
Integrating React.js with PHP projects
Integrating React.js with PHP projectsIntegrating React.js with PHP projects
Integrating React.js with PHP projectsIgnacio Martín
 
Build Lightweight Web Module
Build Lightweight Web ModuleBuild Lightweight Web Module
Build Lightweight Web ModuleMorgan Cheng
 
Why You Should Use TAPIs
Why You Should Use TAPIsWhy You Should Use TAPIs
Why You Should Use TAPIsJeffrey Kemp
 
No more promises lets RxJS 2 Edit
No more promises lets RxJS 2 EditNo more promises lets RxJS 2 Edit
No more promises lets RxJS 2 EditIlia Idakiev
 
Project Lambda: Evolution of Java
Project Lambda: Evolution of JavaProject Lambda: Evolution of Java
Project Lambda: Evolution of JavaCan Pekdemir
 
Workshop 26: React Native - The Native Side
Workshop 26: React Native - The Native SideWorkshop 26: React Native - The Native Side
Workshop 26: React Native - The Native SideVisual Engineering
 
Spring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard WolffSpring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard WolffJAX London
 
Architecture for scalable Angular applications (with introduction and extende...
Architecture for scalable Angular applications (with introduction and extende...Architecture for scalable Angular applications (with introduction and extende...
Architecture for scalable Angular applications (with introduction and extende...Paweł Żurowski
 

What's hot (20)

Reactive Programming with JavaScript
Reactive Programming with JavaScriptReactive Programming with JavaScript
Reactive Programming with JavaScript
 
Why is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosWhy is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenarios
 
Angular 2 introduction
Angular 2 introductionAngular 2 introduction
Angular 2 introduction
 
Oleksandr Tolstykh
Oleksandr TolstykhOleksandr Tolstykh
Oleksandr Tolstykh
 
Integrating React.js with PHP projects
Integrating React.js with PHP projectsIntegrating React.js with PHP projects
Integrating React.js with PHP projects
 
Build Lightweight Web Module
Build Lightweight Web ModuleBuild Lightweight Web Module
Build Lightweight Web Module
 
Why You Should Use TAPIs
Why You Should Use TAPIsWhy You Should Use TAPIs
Why You Should Use TAPIs
 
No more promises lets RxJS 2 Edit
No more promises lets RxJS 2 EditNo more promises lets RxJS 2 Edit
No more promises lets RxJS 2 Edit
 
Angular mix chrisnoring
Angular mix chrisnoringAngular mix chrisnoring
Angular mix chrisnoring
 
SCALA - Functional domain
SCALA -  Functional domainSCALA -  Functional domain
SCALA - Functional domain
 
P1C3 Etiquetas JavaServer Faces al detalle
P1C3 Etiquetas JavaServer Faces al detalleP1C3 Etiquetas JavaServer Faces al detalle
P1C3 Etiquetas JavaServer Faces al detalle
 
Extensible Data Modeling
Extensible Data ModelingExtensible Data Modeling
Extensible Data Modeling
 
Mongo db
Mongo dbMongo db
Mongo db
 
Project Lambda: Evolution of Java
Project Lambda: Evolution of JavaProject Lambda: Evolution of Java
Project Lambda: Evolution of Java
 
Workshop 26: React Native - The Native Side
Workshop 26: React Native - The Native SideWorkshop 26: React Native - The Native Side
Workshop 26: React Native - The Native Side
 
Spring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard WolffSpring Day | Spring and Scala | Eberhard Wolff
Spring Day | Spring and Scala | Eberhard Wolff
 
Oop in java script
Oop in java scriptOop in java script
Oop in java script
 
Architecture for scalable Angular applications (with introduction and extende...
Architecture for scalable Angular applications (with introduction and extende...Architecture for scalable Angular applications (with introduction and extende...
Architecture for scalable Angular applications (with introduction and extende...
 
Typescript barcelona
Typescript barcelonaTypescript barcelona
Typescript barcelona
 
Firebase ng2 zurich
Firebase ng2 zurichFirebase ng2 zurich
Firebase ng2 zurich
 

Similar to Intro to GraphQL on Android with Apollo DroidconNYC 2017

APIdays Paris 2018 - Building scalable, type-safe GraphQL servers from scratc...
APIdays Paris 2018 - Building scalable, type-safe GraphQL servers from scratc...APIdays Paris 2018 - Building scalable, type-safe GraphQL servers from scratc...
APIdays Paris 2018 - Building scalable, type-safe GraphQL servers from scratc...apidays
 
MongoDB World 2019: Building a GraphQL API with MongoDB, Prisma, & TypeScript
MongoDB World 2019: Building a GraphQL API with MongoDB, Prisma, & TypeScriptMongoDB World 2019: Building a GraphQL API with MongoDB, Prisma, & TypeScript
MongoDB World 2019: Building a GraphQL API with MongoDB, Prisma, & TypeScriptMongoDB
 
MongoDB.local Berlin: Building a GraphQL API with MongoDB, Prisma and Typescript
MongoDB.local Berlin: Building a GraphQL API with MongoDB, Prisma and TypescriptMongoDB.local Berlin: Building a GraphQL API with MongoDB, Prisma and Typescript
MongoDB.local Berlin: Building a GraphQL API with MongoDB, Prisma and TypescriptMongoDB
 
Apache Spark, the Next Generation Cluster Computing
Apache Spark, the Next Generation Cluster ComputingApache Spark, the Next Generation Cluster Computing
Apache Spark, the Next Generation Cluster ComputingGerger
 
Next-generation API Development with GraphQL and Prisma
Next-generation API Development with GraphQL and PrismaNext-generation API Development with GraphQL and Prisma
Next-generation API Development with GraphQL and PrismaNikolas Burk
 
Tomer Elmalem - GraphQL APIs: REST in Peace - Codemotion Milan 2017
Tomer Elmalem - GraphQL APIs: REST in Peace - Codemotion Milan 2017Tomer Elmalem - GraphQL APIs: REST in Peace - Codemotion Milan 2017
Tomer Elmalem - GraphQL APIs: REST in Peace - Codemotion Milan 2017Codemotion
 
Intro to Spark and Spark SQL
Intro to Spark and Spark SQLIntro to Spark and Spark SQL
Intro to Spark and Spark SQLjeykottalam
 
Overview of GraphQL & Clients
Overview of GraphQL & ClientsOverview of GraphQL & Clients
Overview of GraphQL & ClientsPokai Chang
 
Google apps script database abstraction exposed version
Google apps script database abstraction   exposed versionGoogle apps script database abstraction   exposed version
Google apps script database abstraction exposed versionBruce McPherson
 
JakartaData-JCon.pptx
JakartaData-JCon.pptxJakartaData-JCon.pptx
JakartaData-JCon.pptxEmilyJiang23
 
Introduction to Scalding and Monoids
Introduction to Scalding and MonoidsIntroduction to Scalding and Monoids
Introduction to Scalding and MonoidsHugo Gävert
 
Building a GraphQL API in PHP
Building a GraphQL API in PHPBuilding a GraphQL API in PHP
Building a GraphQL API in PHPAndrew Rota
 
Let's start GraphQL: structure, behavior, and architecture
Let's start GraphQL: structure, behavior, and architectureLet's start GraphQL: structure, behavior, and architecture
Let's start GraphQL: structure, behavior, and architectureAndrii Gakhov
 
GraphQL & Prisma from Scratch
GraphQL & Prisma from ScratchGraphQL & Prisma from Scratch
GraphQL & Prisma from ScratchNikolas Burk
 
Scala4sling
Scala4slingScala4sling
Scala4slingday
 
Scalable web application architecture
Scalable web application architectureScalable web application architecture
Scalable web application architecturepostrational
 
Developing and maintaining a Java GraphQL back-end: The less obvious - Bojan ...
Developing and maintaining a Java GraphQL back-end: The less obvious - Bojan ...Developing and maintaining a Java GraphQL back-end: The less obvious - Bojan ...
Developing and maintaining a Java GraphQL back-end: The less obvious - Bojan ...Codemotion
 

Similar to Intro to GraphQL on Android with Apollo DroidconNYC 2017 (20)

APIdays Paris 2018 - Building scalable, type-safe GraphQL servers from scratc...
APIdays Paris 2018 - Building scalable, type-safe GraphQL servers from scratc...APIdays Paris 2018 - Building scalable, type-safe GraphQL servers from scratc...
APIdays Paris 2018 - Building scalable, type-safe GraphQL servers from scratc...
 
MongoDB World 2019: Building a GraphQL API with MongoDB, Prisma, & TypeScript
MongoDB World 2019: Building a GraphQL API with MongoDB, Prisma, & TypeScriptMongoDB World 2019: Building a GraphQL API with MongoDB, Prisma, & TypeScript
MongoDB World 2019: Building a GraphQL API with MongoDB, Prisma, & TypeScript
 
MongoDB.local Berlin: Building a GraphQL API with MongoDB, Prisma and Typescript
MongoDB.local Berlin: Building a GraphQL API with MongoDB, Prisma and TypescriptMongoDB.local Berlin: Building a GraphQL API with MongoDB, Prisma and Typescript
MongoDB.local Berlin: Building a GraphQL API with MongoDB, Prisma and Typescript
 
Apache Spark, the Next Generation Cluster Computing
Apache Spark, the Next Generation Cluster ComputingApache Spark, the Next Generation Cluster Computing
Apache Spark, the Next Generation Cluster Computing
 
Next-generation API Development with GraphQL and Prisma
Next-generation API Development with GraphQL and PrismaNext-generation API Development with GraphQL and Prisma
Next-generation API Development with GraphQL and Prisma
 
Tomer Elmalem - GraphQL APIs: REST in Peace - Codemotion Milan 2017
Tomer Elmalem - GraphQL APIs: REST in Peace - Codemotion Milan 2017Tomer Elmalem - GraphQL APIs: REST in Peace - Codemotion Milan 2017
Tomer Elmalem - GraphQL APIs: REST in Peace - Codemotion Milan 2017
 
Intro to Spark and Spark SQL
Intro to Spark and Spark SQLIntro to Spark and Spark SQL
Intro to Spark and Spark SQL
 
Overview of GraphQL & Clients
Overview of GraphQL & ClientsOverview of GraphQL & Clients
Overview of GraphQL & Clients
 
Google apps script database abstraction exposed version
Google apps script database abstraction   exposed versionGoogle apps script database abstraction   exposed version
Google apps script database abstraction exposed version
 
JakartaData-JCon.pptx
JakartaData-JCon.pptxJakartaData-JCon.pptx
JakartaData-JCon.pptx
 
Introduction to Scalding and Monoids
Introduction to Scalding and MonoidsIntroduction to Scalding and Monoids
Introduction to Scalding and Monoids
 
Building a GraphQL API in PHP
Building a GraphQL API in PHPBuilding a GraphQL API in PHP
Building a GraphQL API in PHP
 
Let's start GraphQL: structure, behavior, and architecture
Let's start GraphQL: structure, behavior, and architectureLet's start GraphQL: structure, behavior, and architecture
Let's start GraphQL: structure, behavior, and architecture
 
Coding Ajax
Coding AjaxCoding Ajax
Coding Ajax
 
GraphQL & Prisma from Scratch
GraphQL & Prisma from ScratchGraphQL & Prisma from Scratch
GraphQL & Prisma from Scratch
 
Scala4sling
Scala4slingScala4sling
Scala4sling
 
Scalable web application architecture
Scalable web application architectureScalable web application architecture
Scalable web application architecture
 
Developing and maintaining a Java GraphQL back-end: The less obvious - Bojan ...
Developing and maintaining a Java GraphQL back-end: The less obvious - Bojan ...Developing and maintaining a Java GraphQL back-end: The less obvious - Bojan ...
Developing and maintaining a Java GraphQL back-end: The less obvious - Bojan ...
 
Coding Ajax
Coding AjaxCoding Ajax
Coding Ajax
 
Intake 37 ef2
Intake 37 ef2Intake 37 ef2
Intake 37 ef2
 

More from Mike Nakhimovich

Dispatching Reactive State
Dispatching Reactive StateDispatching Reactive State
Dispatching Reactive StateMike Nakhimovich
 
Data Loading Made Easy with Mike Nakhimovich DroidCon Italy 2017
Data Loading Made Easy with Mike Nakhimovich DroidCon Italy 2017Data Loading Made Easy with Mike Nakhimovich DroidCon Italy 2017
Data Loading Made Easy with Mike Nakhimovich DroidCon Italy 2017Mike Nakhimovich
 
Advanced Dagger talk from 360andev
Advanced Dagger talk from 360andevAdvanced Dagger talk from 360andev
Advanced Dagger talk from 360andevMike Nakhimovich
 
Sword fighting with Dagger GDG-NYC Jan 2016
 Sword fighting with Dagger GDG-NYC Jan 2016 Sword fighting with Dagger GDG-NYC Jan 2016
Sword fighting with Dagger GDG-NYC Jan 2016Mike Nakhimovich
 
Intro to Functional Programming with RxJava
Intro to Functional Programming with RxJavaIntro to Functional Programming with RxJava
Intro to Functional Programming with RxJavaMike Nakhimovich
 

More from Mike Nakhimovich (7)

meetstore5.pdf
meetstore5.pdfmeetstore5.pdf
meetstore5.pdf
 
Dispatching Reactive State
Dispatching Reactive StateDispatching Reactive State
Dispatching Reactive State
 
Data Loading Made Easy with Mike Nakhimovich DroidCon Italy 2017
Data Loading Made Easy with Mike Nakhimovich DroidCon Italy 2017Data Loading Made Easy with Mike Nakhimovich DroidCon Italy 2017
Data Loading Made Easy with Mike Nakhimovich DroidCon Italy 2017
 
Open sourcing the store
Open sourcing the storeOpen sourcing the store
Open sourcing the store
 
Advanced Dagger talk from 360andev
Advanced Dagger talk from 360andevAdvanced Dagger talk from 360andev
Advanced Dagger talk from 360andev
 
Sword fighting with Dagger GDG-NYC Jan 2016
 Sword fighting with Dagger GDG-NYC Jan 2016 Sword fighting with Dagger GDG-NYC Jan 2016
Sword fighting with Dagger GDG-NYC Jan 2016
 
Intro to Functional Programming with RxJava
Intro to Functional Programming with RxJavaIntro to Functional Programming with RxJava
Intro to Functional Programming with RxJava
 

Recently uploaded

Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksSoftradix Technologies
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
Snow Chain-Integrated Tire for a Safe Drive on Winter Roads
Snow Chain-Integrated Tire for a Safe Drive on Winter RoadsSnow Chain-Integrated Tire for a Safe Drive on Winter Roads
Snow Chain-Integrated Tire for a Safe Drive on Winter RoadsHyundai Motor Group
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
Azure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAzure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAndikSusilo4
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
Next-generation AAM aircraft unveiled by Supernal, S-A2
Next-generation AAM aircraft unveiled by Supernal, S-A2Next-generation AAM aircraft unveiled by Supernal, S-A2
Next-generation AAM aircraft unveiled by Supernal, S-A2Hyundai Motor Group
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxOnBoard
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 

Recently uploaded (20)

The transition to renewables in India.pdf
The transition to renewables in India.pdfThe transition to renewables in India.pdf
The transition to renewables in India.pdf
 
Benefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other FrameworksBenefits Of Flutter Compared To Other Frameworks
Benefits Of Flutter Compared To Other Frameworks
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
Snow Chain-Integrated Tire for a Safe Drive on Winter Roads
Snow Chain-Integrated Tire for a Safe Drive on Winter RoadsSnow Chain-Integrated Tire for a Safe Drive on Winter Roads
Snow Chain-Integrated Tire for a Safe Drive on Winter Roads
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Azure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAzure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & Application
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
Next-generation AAM aircraft unveiled by Supernal, S-A2
Next-generation AAM aircraft unveiled by Supernal, S-A2Next-generation AAM aircraft unveiled by Supernal, S-A2
Next-generation AAM aircraft unveiled by Supernal, S-A2
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptx
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 

Intro to GraphQL on Android with Apollo DroidconNYC 2017

  • 1. Query DroidConNYC{ slide(id: "1") { Title Authors Company } } { Title: "Intro to GraphQL on Android", Authors: ["Brian Plummer","Mike Nakhimovich"], Company: "The New York Times" }
  • 2. We work at The New York Times We do a lot of data loading
  • 3. Recently, our team moved from using RESTful APIs to GraphQL for our data loading architecture
  • 4. What’s GraphQL? • A query language for APIs and a runtime for fulfilling those queries with your existing data • Alternative to RESTful API • Client driven - get only data you need • Works on iOS, Android, Web
  • 5. GraphQL was created by Facebook as a new standard for server/client data transfer • Give front end developers an efficient way to ask for minimal data • Give server-side developers a robust way to get their data out to their users
  • 6. GraphQL is As Easy as 1-2-3 • Describe your data • Ask for what you want • Get predictable results
  • 7. Describe Your Data in a Schema type Character { name: String! appearsIn: [Episode]! }
  • 8. Describe Your Data in a Schema type Character { name: String! appearsIn: [Episode]! } Character is a GraphQL Object Type, meaning it's a type with some fields. Most of the types in your schema will be object types.
  • 9. Describe Your Data in a Schema type Character { name: String! appearsIn: [Episode]! } name and appearsIn are fields on the Character type. That means that name and appearsIn are the only fields that can appear in any part of a GraphQL query that operates on the Character type.
  • 10. Describe Your Data in a Schema type Character { name: String! appearsIn: [Episode]! } String is one of the built-in scalar types. These are types that resolve to a single scalar object and can't have sub-selections in the query.
  • 11. GraphQL Example Schema type Character { name: String! appearsIn: [Episode]! } String! means that the field is non-nullable, meaning that the GraphQL service promises to always give you a value when you query this field.
  • 12. GraphQL Example Schema type Character { name: String! appearsIn: [Episode]! } [Episode]! represents an array of Episode objects. Since it is also non-nullable, you can always expect an array (with zero or more items) when you query the appearsIn field.
  • 13. Ask for what you need get predictable results
  • 14. Combine Resources into One Request { hero { name # Queries can have comments friends { name } } }
  • 15. Combine Resources into One Request { hero { name # Queries can have comments friends { name } } }
  • 16. Reuse Fields in a Fragment { leftColumn: hero(episode: EMPIRE) { ...comparisonFields } rightColumn: hero(episode: JEDI) { ...comparisonFields } } fragment comparisonFields on Character { name appearsIn }
  • 17. Reuse Fields in a Fragment { leftColumn: hero(episode: EMPIRE) { ...comparisonFields } rightColumn: hero(episode: JEDI) { ...comparisonFields } } fragment comparisonFields on Character { name appearsIn }
  • 18. Example: Loading Data from Github Using REST vs GraphQL
  • 19. On any platform, data loading consists of these steps: 1. Model Data 2. Network 3. Transform 4. Persist
  • 20. How does REST look on Android?
  • 21. ...It Looks Like a lot of Dependencies Data Modeling Networking Storage Transform Immutables OKhttp Store Gson Curl Retrofit SqlDelight RxJava Yes, those are all needed !
  • 22. Start with Inspection curl -i "https://api.github.com/repos/vmg/redcarpet/issues?state=closed"
  • 23. Model Your Data interface Issue { User user(); String url(); interface User { long id(); String name(); } } Error prone even with code generation
  • 24. Data Modeling with Immutables @Value.Immutable interface Issue { User user(); String url(); @Value.Immutable interface User { long id(); String name(); } } Error Prone even with Code Generation
  • 25. Data Parsing with Gson @Gson.TypeAdapters @Value.Immutable interface Issue { User user(); String url(); @Value.Immutable interface User { long id(); String name(); } }
  • 26. Networking open fun provideRetrofit(gson: Gson, okHttpClient: OkHttpClient): GithubApi { return Retrofit.Builder() .client(okHttpClient) .baseUrl(BuildConfig.BASE_URL) .addConverterFactory(GsonConverterFactory.create(gson)) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build() .create(GithubApi::class.java!!)}
  • 27. Storage CREATE TABLE issue ( _id LONG PRIMARY KEY AUTOINCREMENT, id LONG NOT NULL, url STRING, title STRING, comments INT NOT NULL }
  • 28. Storage public abstract class Issue implements IssueModel { public static final Mapper<Issue> MAPPER = new Mapper<>((Mapper.Creator<Issue>) ImmutableIssue::of); public static final class Marshal extends IssueMarshal { } }
  • 29. Storage long insertIssue(Issue issue) { if (recordExists(Issue.TABLE_NAME, Issue.ID, String.valueOf(issue.id()))) { return 0; } return db.insert(Issue.TABLE_NAME, new Issue.Marshal() .url(issue.url()) .id(issue.id())); }
  • 30. Storage - Memory StoreBuilder.parsedWithKey<GitHubOrgId, BufferedSource, Issues>() .fetcher(fetcher) .persister(persister) .parser(parser) .memoryPolicy(MemoryPolicy .builder() .setMemorySize(11L) .setExpireAfterWrite(TimeUnit.HOURS.toSeconds(24)) .setExpireAfterTimeUnit(TimeUnit.SECONDS) .build()) .networkBeforeStale() .open()
  • 31. That's a Good Architecture It's also not something we can expect a beginner to know
  • 32. REST Feels Like Legacy Tech Well-established and with great tools, but cumbersome to work with
  • 33. Thanks to Facebook, there's a new kid on the block GraphQL
  • 34. Now, Let's See GraphQL on Android
  • 35. We can't since Facebook didn't open source an Android Client, Thanks for your time and goodnight !
  • 36. Just Kidding, Community to the Rescue!
  • 37. Introducing Apollo-Android GraphQL Apollo Android was developed by Shopify, New York Times, & AirBnb as an Open Source GraphQL solution.
  • 38. Apollo-Android • Built by Android devs for Android devs • A strongly-typed, caching GraphQL client for Android • Rich support for types and type mappings • Code generation for the messy parts • Query validation at compilation
  • 39. Meets Facebook's GraphQL Spec • Works with any GraphQL Query • Fragments • Union Types • Nullability • Deprecation
  • 40. Apollo Reduces Setup to Work with a Backend Data Modeling Networking Storage Transform Github Explorer OKhttp Apollo RxJava Apollo Apollo Apollo Apollo You Ain't Gonna Need It Retrofit | Immutables| Gson | Guava | SqlDelight/Brite | Store | Curl | JsonViewer.hu
  • 41. Apollo-Android Has 2 Main Parts • Gradle Plugin Apollo code generation plugin • Runtime Apollo client for executing operations
  • 43. Add Apollo Dependencies build.gradle: dependencies { classpath 'com.apollographql.apollo:gradle-plugin:0.4.1' } app/build.gradle: apply plugin: 'com.apollographql.android' ..... //optional RxSupport compile 'com.apollographql.apollo:apollo-rx-support:0.4.1'
  • 44. Create a Standard GraphQL Query Queries have params and define shape of response organization(login:”nyTimes”){ repositories(first:6) { Name } }
  • 45. Leave Your CURL at Home Most GraphQL Servers have a GUI (GraphiQL) https://developer.github.com/v4/explorer/
  • 46. GraphiQL: Explore Schema and Build Queries • Shape of Response • Nullability Rules • Enum values • Types
  • 48. Add Schema & RepoQuery.graphql to project & compile
  • 49. Apollo Writes Code So You Don't Have To private fun CodeGenerationIR.writeJavaFiles(context: CodeGenerationContext, outputDir: File, outputPackageName: String?) { fragments.forEach { val typeSpec = it.toTypeSpec(context.copy()) JavaFile.builder(context.fragmentsPackage, typeSpec).build().writeTo(outputDir) } typesUsed.supportedTypeDeclarations().forEach { val typeSpec = it.toTypeSpec(context.copy()) JavaFile.builder(context.typesPackage, typeSpec).build().writeTo(outputDir) } if (context.customTypeMap.isNotEmpty()) { val typeSpec = CustomEnumTypeSpecBuilder(context.copy()).build() JavaFile.builder(context.typesPackage, typeSpec).build().writeTo(outputDir) } operations.map { OperationTypeSpecBuilder(it, fragments, context.useSemanticNaming) } .forEach { val packageName = outputPackageName ?: it.operation.filePath.formatPackageName() val typeSpec = it.toTypeSpec(context.copy()) JavaFile.builder(packageName, typeSpec).build().writeTo(outputDir) } } Actually Ivan(sav007) Does (He's Awesome)
  • 50. Builder - For Creating Your Request Instance ///api val query = RepoQuery.builder.name("nytimes").build() //Generated Code public static final class Builder { private @Nonnull String name; Builder() { } public Builder name(@Nonnull String name) { this.name = name; return this; } public RepoQuery build() { if (name == null) throw new IllegalStateException("name can't be null"); return new RepoQuery(name); } }
  • 51. Notice How Our Request Param name is Validated ///api val query = RepoQuery.builder.name("nytimes").build() //Generated Code public static final class Builder { private @Nonnull String name; Builder() { } public Builder name(@Nonnull String name) { this.name = name; return this; } public RepoQuery build() { if (name == null) throw new IllegalStateException("name can't be null"); return new RepoQuery(name); } }
  • 52. Response Models public static class Repositories { final @Nonnull String __typename; final int totalCount; final @Nullable List<Edge> edges; private volatile String $toString; private volatile int $hashCode; private volatile boolean $hashCodeMemoized; public @Nonnull String __typename() { return this.__typename; } //Identifies the total count of items in the connection. public int totalCount() {return this.totalCount;} //A list of edges. public @Nullable List<Edge> edges() {return this.edges;} @Override public String toString() {...} @Override public boolean equals(Object o) { ... } @Override public int hashCode() {...}
  • 53. Mapper - Reflection-Free Parser public static final class Mapper implements ResponseFieldMapper<Repositories> { final Edge.Mapper edgeFieldMapper = new Edge.Mapper(); @Override public Repositories map(ResponseReader reader) { final String __typename = reader.readString($responseFields[0]); final int totalCount = reader.readInt($responseFields[1]); final List<Edge> edges = reader.readList($responseFields[2], new ResponseReader.ListReader<Edge>() { @Override public Edge read(ResponseReader.ListItemReader reader) { return reader.readObject(new ResponseReader.ObjectReader<Edge>() { @Override public Edge read(ResponseReader reader) { return edgeFieldMapper.map(reader); } }); } }); return new Repositories(__typename, totalCount, edges); }} Can parse 20MB Response w/o OOM
  • 54. Querying Github's API With Apollo Client
  • 55. Building an Apollo Client ApolloClient.builder() .serverUrl("https://api.github.com/graphql) .okHttpClient(okhttp) .build();
  • 56. Querying a Backend query = RepoQuery.builder().name("nytimes").build()
  • 57. Querying a Backend query = RepoQuery.builder().name("nytimes").build() ApolloQueryCall githubCall = apolloClient.query(query);
  • 58. Querying a Backend query = RepoQuery.builder().name("nytimes").build() ApolloQueryCall githubCall = apolloClient.query(query); githubCall.enqueue(new ApolloCall.Callback<>() { @Override public void onResponse(@Nonnull Response<> response) { handleResponse(response); } @Override public void onFailure(@Nonnull ApolloException e) { handleFailure(e); } });
  • 60. Storage with Apollo is done through Caches • HTTP • Normalized
  • 61. HTTP Caching • Similar to OKHTTP Cache (LRU) • Streams response to cache same time as parsing • Can Set Max Cache Size • Useful for background updating to prefill cache • Prefetching apolloClient.prefetch(new RepoQuery("nytimes"));
  • 62. HTTP Caching - as well as you can do in REST Apollo Introduces a Normalized Cache Apollo Store
  • 63. Apollo Store • Allows multiple queries to share same cached values • Great for things like master/detail • Caching is done post-parsing • Each field is cached individually • Apollo ships with both an in memory and a disk implementation of an Apollo Store • You can even use both at same time
  • 64. How Does Apollo Store Work? • Each Object in Response will have its own record with ID • All Scalars/Members will be merged together as fields • When we are reading from Apollo, it will seamlessly read from Apollo Store or network
  • 65. Setup Bi-Level Caching with Apollo Store //Create DB ApolloSqlHelper apolloSqlHelper = ApolloSqlHelper.create(context, "db_name"); //Create NormalizedCacheFactory NormalizedCacheFactory normalizedCacheFactory = new LruNormalizedCacheFactory(EvictionPolicy.NO_EVICTION) .chain(new SqlNormalizedCacheFactory(apolloSqlHelper));
  • 66. Create a Cache Key Resolver //Create the cache key resolver CacheKeyResolver cacheKeyResolver = new CacheKeyResolver() { @Nonnull @Override public CacheKey fromFieldRecordSet(@Nonnull ResponseField field, @Nonnull Map<String, Object> recordSet) { String typeName = (String) recordSet.get("__typename"); if (recordSet.containsKey("id")) { String typeNameAndIDKey = recordSet.get("__typename") + "." + recordSet.get("id"); return CacheKey.from(typeNameAndIDKey); } return CacheKey.NO_KEY; } @Nonnull @Override public CacheKey fromFieldArguments(@Nonnull ResponseField field, @Nonnull Operation.Variables variables) { return CacheKey.NO_KEY; } };
  • 67. Init Apollo Client With a Cache //Build the Apollo Client ApolloClient apolloClient = ApolloClient.builder() .serverUrl("/") .normalizedCache(cacheFactory, resolver) .okHttpClient(okHttpClient) .build();
  • 68. Don't Like Our Cache? BYO Cache public abstract class NormalizedCache { @Nullable public abstract Record loadRecord(@Nonnull String key, @Nonnull CacheHeaders cacheHeaders) @Nonnull public Collection<Record> loadRecords(@Nonnull Collection<String> keys, @Nonnull CacheHeaders cacheHeaders) @Nonnull public abstract Set<String> merge(@Nonnull Record record, @Nonnull CacheHeaders cacheHeaders) public abstract void clearAll() public abstract boolean remove(@Nonnull CacheKey cacheKey)
  • 69. Apollo Is Reactive QueryWatcher is a listener for changes to any fields in a query. • When a dependent field changes in the Apollo Store, QueryWatcher will re-emit the response. • QueryWatcher ~ endless subscription to a particular query. Insert Example of a query watcher
  • 70. Bonus: Includes RxJava Bindings RxApollo.from(apolloClient.query(RepoQuery.builder().name("nytimes").build())) .map(dataResponse -> dataResponse .data() .organization() .repositories()) .subscribe(view::showRepositories, view::showError) RxApollo response can be transformed into LiveData
  • 71. Version 1.0 ships soon! • 380 commits • 1000s of tests • 18 contributors including devs from Shopify, Airbnb, NY Times • Come join us at https://github.com/apollographql/apollo- android