What do you want?
Use latest libraries!
So let's upgrade!
But... there are issues...
Who'll fix them
Not me
Not me
Let's wait...
Upgrade with confidence
@ktrz__ | /ktrz
05.12.2018, FrontendCon
Chris Trześniewski
Senior Frontend Developer @Scalac
https://slides.com/ktrz/fc2018
What's the story?
What's the story
Project using Angular
GraphQL API
Apollo Client (angular-apollo)
What's the motivation?
What's the motivation
Easier to customize
Clearer API
Query batching
Integration with NgRx
Ok, so let's just upgrade - right?
Let's upgrade
Clear upgrade path
API changed a bit
...
Let's upgrade
...
It seems ready... npm start
this.apollo.watchQuery({
query: foo,
variables: { a: a$, b: b$, c: c$ },
})
.subscribe((bar) => {
console.log(bar);
});
this.apollo.watchQuery({
query: foo,
variables: { a: a$, b: b$, c: c$ },
})
.valueChanges
.subscribe((bar) => {
console.log(bar);
});
Title Text
Keep calm!
Long story short
Long story short
❌ no Observable variables
Long story short
this.apollo.watchQuery({
query: foo,
variables: { a: a$, b: b$, c: c$ },
})
.valueChanges
.subscribe((bar) => {
console.log(bar);
});
Long story short
First solution
First solution
const variables$ = combineVariables({ a: a$, b: a$, c: c$ });
// {a: Observable, b: Observable, c: Observable} => Observable<{a,b,c}>
variables$.pipe(
switchMap(variables => {
return this.apollo.watchQuery({
query: foo,
variables: variables,
}).valueChanges;
}
)
)
.subscribe((bar) => {
console.log(bar);
});
It works!
New watchQuery everytime
Second solution
const variables$ = combineVariables({a: a$, b: a$, c: c$});
// {a: Observable, b: Observable, c: Observable} => Observable<{a,b,c}>
const queryRef = this.apollo.watchQuery({
query: foo,
fetchResults: false,
});
variables$.pipe(
tap(variables => queryRef.setVariables(variables)),
switchMap(() => queryRef.valueChanges)
)
.subscribe((bar) => {
console.log(bar);
});
Only one watchQuery
Let's back up a little
Let's back up a little
this.apollo.watchQuery({
query: foo,
variables: { a: a$, b: a$, c: c$ },
})
.subscribe((bar) => {
console.log(bar);
});
const variables$ = combineVariables({a: a$, b: a$, c: c$});
// {a: Observable, b: Observable, c: Observable} => Observable<{a,b,c}>
const queryRef = this.apollo.watchQuery({
query: foo,
variables: variables,
fetchResults: false,
});
variables$.pipe(
tap(variables => queryRef.setVariables(variables)),
switchMap(() => queryRef.valueChanges)
)
.subscribe((bar) => {
console.log(bar);
});
The ultimate goal
The ultimate goal
this.apollo.watchQuery({
query: foo,
variables: { a: a$, b: a$, c: c$ },
})
.subscribe((bar) => {
console.log(bar);
});
Middleware to the rescue!
The ultimate goal
export function createApollo(httpLink: HttpLink): ApolloClientOptions<any> {
return {
link: from([
handleObservableVariables(),
httpLink.create({ uri })
]),
cache: new InMemoryCache(),
};
}
Using middleware
The ultimate goal
export const handleObservableVariables = (ngZone: NgZone) =>
new RxjsLink({ onOperation: requestHandler(ngZone) });
return operation$.pipe(
switchMap(operation => {
const context = operation.getContext();
const requestHandler = (zone: NgZone): OnOperation =>
(operation$: Observable<Operation>): Observable<Operation> =>
zone.runOutsideAngular(() => {
if (checkVariables(context.variables$) {
return combineVariables(context.variables$).pipe(
switchMap(variables =>
of(prepareOperation(operation, variables)))
);
}
return of(operation);
}),
);
});
Ultimate goal?
well... almost
The ultimate goal
this.apollo.watchQuery({
query: foo,
context: {
variables$: { a: a$, b: a$, c: c$ },
},
fetchResults: false,
})
.subscribe((bar) => {
console.log(bar);
});
this.apollo.watchQuery({
query: foo,
variables: { a: a$, b: a$, c: c$ },
})
.subscribe((bar) => {
console.log(bar);
});
Still... it's nice already :)
Thank you!
Upgrade with confidence
By Chris Trześniewski
Upgrade with confidence
- 666