9th Nov 2016

Berlin


3


2


1

GO!

Hallo

Ich bin Kamil

back to English...

Warsaw

Berlin

some sea

some sea

some sea

some border

some border

some border

some border

some city

some city

some city

some city

some city

some city

some city

some city

I live here

you live here

kamilkisiela

GraphQL and Angular

Landing on the ngMoon with Apollo


today

components

components

app is based on components

app

components

app = component

app

data

components need data




    @Component({
      template: `
        Author: {{comment.author}}
        Text: {{comment.text}}
      `
    })
    class CommentComponent {
      comment: Comment;
    }

data

provide it directly




    @Component({
      template: `
        Author: {{comment?.author}}
        Text: {{comment?.text}}
      `
    })
    class CommentComponent {
      comment: Comment;
      @Input() commentId: number;

      constructor(private http: Http) {}

      ngOnInit() {

        this.http.get(`https://api.com/comment/${this.commentId}`)
          .map(res => res.json())
          .subscribe((comment) => this.comment = comment);

      }
    }

problem?

where is the problem?

with data

managing data is not ideal now

there must be a better way!

components

Smart

Dumb

Container

Presentational

=

components

what it means "smart and dumb"?

data

provide

display

Smart component

Dumb component

back to the example

data

data is provided directly




    @Component({
      template: `
        Author: {{comment?.author}}
        Text: {{comment?.text}}
      `
    })
    class CommentComponent {
      comment: Comment;
      @Input() commentId: number;

      constructor(private http: Http) {}

      ngOnInit() {

        this.http.get(`https://api.com/comment/${this.commentId}`)
          .map(res => res.json())
          .subscribe((comment) => this.comment = comment);

      }
    }

data

make it dumb




    @Component({
      template: `
        Author: {{comment?.author}}
        Text: {{comment?.text}}
      `
    })
    class CommentComponent {
      @Input() comment: Comment;
    }

data

add the brain




    @Component({
      template: `
        <comment [comment]="comment | async"></comment>
      `
    })
    class CommentContainerComponent {
      @Input() commentId: number;
      comment: Observable<Comment>;

      constructor(private http: Http) {}

      ngOnInit() {

        this.comment = this.http
          .get(`https://api.com/comment/${this.commentId}`)
          .map(res => res.json())

      }
    }

still not a good idea

services!

yes, services, we love them!

service

use a service to handle data fetching




    @Component({
      template: `
        <comment [comment]="comment | async"></comment>
      `
    })
    class CommentContainerComponent {
      @Input() commentId: number;
      comment: Observable<Comment>;

      constructor(private commentsApi: CommentsApi) {}

      ngOnInit() {

        this.comment = this.commentsApi.single(this.commentId);

      }
    }

pff... done

now everyone is happy

besides your clients...

and your developers!


problems

overloaded network

overloaded network

API

http

unnecessary requests

unnecessary requests

API

http

comment #1

comment #3

comment #4

comment #2

inconsistent data

inconsistent data

time

comment

comment

{

  id: 13

  likes: 20

}
{

  id: 13

  likes: 21

}

someone likes the comment

overfetched data

overfetched data

size does matter

GraphQL is awesome!

posted by Kamil

{

  text: "GraphQL is awesome!",

  postedBy: "Kamil",

  createdAt: 1478368227,

  likes: 2

}

adjustments

adjustments

data structure doesn't always fit the actual needs

{

  contents: "GraphQL is awesome!",

  author:   "Kamil"

}
{{comment.text}} 
by
{{comment.postedBy}}

client depends on API

API change requires a reflection in an app


solutions

use GraphQL

THE END

thank you

NOT

"oh no... he continues"

not the end?

they say GraphQL is a cure for everything!

GraphQL is helpful

but... it doesn't solve every of those problems

what it solves

separation

GraphQL makes client totally independent

client depends on API

define what you need

and change it any time you want in any component

overfetched data

own the structure

define exact shape of data you want to use

adjustments

use fragments

bound it with components

use fragments

to define what a component needs


    // Comment component

    CommentInfoFragment = gql`
      fragment CommentInfo on Comment {
        id
        text
        author
      }
    `;

    // CommentsPage Component

    const ALL_COMMENTS_QUERY = gql`
      query getAllComments {
        allComments {
          ...CommentInfo
        }
      }

      ${CommentInfoFragment}
    `;

    this.apollo.watchQuery({
      query: ALL_COMMENTS_QUERY
    });


what about the network?

GraphQL is just a language

back to the example

let's find proper solutions




    @Component({
      template: `
        <comment [comment]="comment | async"></comment>
      `
    })
    class CommentContainerComponent {
      @Input() commentId: number;
      comment: Observable<Comment>;

      constructor(private commentsApi: CommentsApi) {}

      ngOnInit() {

        this.comment = this.commentsApi.single(this.commentId);

      }
    }

back to the example

where we left off

CommentsApi

our service to fetch comments from the API




    class CommentsApi {
      url: string = `https://api.com/comment/`;
 
      constructor(private http: Http) {}
 
      single(id: number) {

        return this.http.get(this.url + id)
          .map(res => res.json());

      }
    }

CommentsApi

how it looks now

implement GraphQL


    class CommentsApi {
      url: string = `https://api.com/query?=`;
 
      constructor(private http: Http) {}
 
      single(id: number) {

        const query = `
          query getComment {
            Comment(id: ${id}) {
              text
              postedBy
            }
          }
        `;

        return this.query(query);

      }

      query(query: string) {

        return this.http.get(this.url + JSON.stringify(query))
          .map(res => res.json().data.comment)

      }
    }

CommentsApi

with GraphQL

catch them all!

and use only one

unnecessary requests

Request batching

wait for some time to catch the same requests

time

10 ms

batching

server

solved for requests

with batching we don't get different results

for the same queries

inconsistent data

caching

use store to keep all the results

overloaded network

caching

use store to cache a query

cache

server

request

UI

bigger and bigger

our service is getting more and more complex

open-source it!

looks like it could be helpful for many people

someone did

somewhere there is a magic tool!

it's called


apollo

what is Apollo?

GraphQL client

solves the problems we talked about

exactly what we need

to create modern web apps

so

we own the network

but...

what about UX?

Apollo to the rescue


UX

latency

users don't like to wait

Optimistic UI

Optimistic UI

don't make them wait

1. We submit a comment

2. Request is made

2. We update the UI in the same moment

3. We get the response from the server later

1.

2.

2.

3.

Optimistic UI

how it works

Mutation

UI

optimistic response

real response

latency yet again

how to make an app even faster?

prefetching

prefetching

without

1. Enter the route

2. Request is made

3. Wait for the response

4. Update the UI

prefetching

with

1. User puts cursor over the link

2. Request is made to fetch the query

3. We put the response inside the cache

4. User enters the page imidiately

real time

get the experience

Subscriptions

Subscriptions

keep things updated

action

server

clients

pub sub

SEO

people should visit!

server side rendering

click the logo to see a working example

server side rendering

prefetch queries on the server

server

client

fetch query

save to store

fetch query

render with the same store

update the UI imidiately

still not enough

make it even faster

Ahead-of-Time

compilation to speed up the runtime

what if...

we could make just one request with all queries

Query Batching

one request per render

Query batching

You can even specify your custom batch interval

time

10 ms

batching

server

interval

cool


angular?
 

only for Angular?

can I use it with other frameworks?

YES!

with Angular 1.X

and many others

all share the same principals


enough

hit me with any questions!

?

it was fun!

feel free to message me

come to Poland!


thanks

*danke

bye bye bye bye bye bye

Made with Slides.com