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!