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

How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfhans926745
 
Evaluating the top large language models.pdf
Evaluating the top large language models.pdfEvaluating the top large language models.pdf
Evaluating the top large language models.pdfChristopherTHyatt
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUK Journal
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdflior mazor
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 

Recently uploaded (20)

How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdf
 
Evaluating the top large language models.pdf
Evaluating the top large language models.pdfEvaluating the top large language models.pdf
Evaluating the top large language models.pdf
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 

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