Test Driving Apollo Client 2.0
by Gerard Sans (@gerardsans)










Google Developer Expert

Master of Ceremonies


Blogger
International Speaker

Spoken at 56 events in 18 countries
Angular Trainer

Community Leader

900
1.2K














Angular In Flip Flops

GraphQL Timeline
2012

GraphQL created at Facebook
2015
GraphQL is open sourced
Relay Classic is open sourced
2016

New GraphQL website graphql.org
First GraphQL Summit
GitHub announces GraphQL API
Angular (v2)

2017

Relay Modern 1.0
Apollo Client 2.0
Angular (v5)


Relay vs Apollo Downloads

launchpad.graphql.com

graphql.com

Developer Tools
Todo App



GraphQL Schema
Type System
- Scalar Types: Int, Float, String, Boolean, ID
- Object Types: Todo
- Entry points: Query, Mutation, Subscription
Schema Syntax
- Optional: String, Todo
- Mandatory: String!, Todo!
- Arrays: [String], [Todo]

npm install --global graphcool graphcool init
graphcool push graphcool console
graphcool-cli

Todos Schema
// project.graphcool
type Todo @model {
id: ID! @isUnique
text: String!
complete: Boolean!
}
demo
Apollo Client
2.0


Apollo
Cache
Apollo Client
Apollo
Link
Apollo Cache
Packages
- apollo-cache-inmemory
- apollo-cache-hermes
InMemoryCache
- Normalised and flattened
- apollo.getClient()
- readQuery, writeQuery
- readFragment, writeFragment
Add Todo
const query = gql`query AllTodos {
allTodoes { id text complete }
}`;
const data = store.readQuery<Todos>({ query });
const newTodo = {
id: createTodo.id,
text: input.value,
complete: false,
__typename: "Todo"
};
store.writeQuery({
query,
data: {
allTodoes: [...data.allTodoes, newTodo],
},
});
Apollo Link
Packages
- apollo-link
- apollo-link-http
- apollo-link-ws
- apollo-link-error
- apollo-link-batch
- apollo-link-polling
- apollo-link-retry
Packages (future)
- apollo-link-store
- apollo-link-rest
- apollo-link-offline
Apollo Link
- concat(link1, link2)
- split(expr, link1, link2)
- from([link1, link2])
Security Headers
export class GraphQLModule {
constructor(
private apollo: Apollo,
private httpLink: HttpLink
) {
const http = httpLink.create();
const authMiddleware = new ApolloLink((operation, forward) => {
operation.setContext({
headers: { 'Authorization': localStorage.getItem('token') || '' }
});
return forward(operation);
});
apollo.create({
link: concat(authMiddleware, http)
});
}
}
Using GraphQL
GraphQL Server

source: blog
Dependencies
- JavaScript client for GraphQL (apollo-client)
- API to run queries and mutations (apollo-angular)
- Apollo Link (apollo-link)
- Store (apollo-cache-inmemory)
- Template literal (graphql-tag)
Setup
@NgModule({
imports: [ HttpClientModule, HttpLinkModule ],
exports: [ ApolloModule ]
})
export class GraphQLModule {
constructor( apollo: Apollo, httpLink: HttpLink ) {
apollo.create({
// localhost/graphql (default)
link: httpLink.create({
uri: GRAPHCOOL_URI
}),
cache: new InMemoryCache(),
});
}
}
Bootstrap
// app.module.ts
import { GraphQLModule } from './graphql.module';
@NgModule({
imports: [
BrowserModule,
GraphQLModule,
],
bootstrap: [AppComponent]
})
export class AppModule { }
Todos Schema
schema {
query: Query,
mutation: Mutation
}
type Todo {
id: ID!
text: String!
complete: Boolean!
}
type Query {
allTodoes(skip: Int, take: Int): [Todo!]!
}
Main APIs
- query (QueryRef)
- watchQuery (QueryRef)
- mutate (Observable)
QueryRef
- valueChanges (Observable)
- subscribeToMore()
- refetch()
- fetchMore()
- start/stopPolling()
query
// app.component.ts
@Component()
export class App {
constructor(private apollo: Apollo){
let query = apollo.query({
query: gql`query todos {
allTodoes { id complete text } }`
});
let subscription = query.valueChanges.subscribe({
next: result => {
// result.loading
// result.data.allTodoes
},
error: error => {
console.log(`Error: ${error.message}`);
}
});
}
}
watchQuery
// todoList.component.ts
@Component({
template:
`<todo *ngFor="let todo of todos | async">{{todo.text}}</todo>`
})
class TodoList implements OnInit {
todos: Observable<any>;
constructor(private apollo: Apollo) { }
ngOnInit() {
const query = this.apollo.watchQuery({ query: todosQuery });
this.todos = query.valueChanges.map(({data}) => data.allTodoes);
}
// onRefresh = query.refetch;
}
mutate
// todo.component.ts
@Component()
export class Todo {
constructor(private apollo: Apollo) { }
private onTodoClick(){
let toggle$ = this.apollo.mutate({
mutation: gql`
mutation toggleTodo($id: ID!, $complete: Boolean!) {
updateTodo(id: $id, complete: $complete) { id text complete }
}`,
variables: { id: this.id, complete: !this.complete },
let subscription = toggle$.subscribe(
({ data }) => { // data.updateTodo.id }
);
}
}
demo
Adding Realtime
GraphQL Server

source: blog
Dependencies
- Apollo link for Websockets
- WebSocket subscriptions
Setup
export class GraphQLModule {
constructor(
private apollo: Apollo,
private httpLink: HttpLink
) {
const link = this.setupLink();
const cache = new InMemoryCache();
apollo.create({ link, cache });
}
}
Setup
private setupLink() {
const http = this.httpLink.create({
uri: GRAPHCOOL_URI
});
const websocket = new WebSocketLink(
new SubscriptionClient(GRAPHCOOL_URI_WS, {
reconnect: true
})
);
const link = ApolloLink.split(
(op) => {
const ast = getOperationAST(op.query, op.operationName);
return ast && ast.operation === 'subscription';
},
/* if true use */ websocket,
/* if false use */ http
);
return link;
}
Todos Schema
schema {
subscription: Subscription
}
type Mutation {
createTodo(text: String!, complete: Boolean!): Todo
deleteTodo(id: ID!): Todo
}
type Subscription {
Todo(filter: [CREATED, UPDATED, DELETED]): {
mutation: [CREATED, UPDATED, DELETED]
node: Todo
updatedFields: [String!]
previousValues: Todo
}
}
subscribeToMore
// app.component.ts
query.subscribeToMore({
document: gql`
subscription {
Todo(filter: { mutation_in: [CREATED] }) {
node {
id
complete
text
}
}
}
`,
updateQuery: (state: Todos, { subscriptionData }) => {
...
}
subscribeToMore
// app.component.ts
updateQuery: (state, { subscriptionData }) => {
const {node: node} = (subscriptionData as any).Todo;
if (!state.allTodoes.find(todo =>
todo.id === node.id)) {
state.allTodoes.push(node);
}
return {
allTodoes: todos
}
}
demo
Why use GraphQL?
Some reasons
- Declarative
- De-coupled from storage
- Validated and structured
- Facilitates Collaboration
- Super fast
More
gsans/todo-apollo-v2




Test driving Apollo Client 2.0
By Gerard Sans
Test driving Apollo Client 2.0
The Apollo team just released the new version of the Apollo Client. There's already a lot of hype around the new architecture using a new modular and flexible approach. In this talk we are going to put it to test together with Angular (v5+). Buckle up!
- 3,100