Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Looking for the right tech stack for GraphQL application

Looking for the right tech stack for GraphQL application

Nikita Galkin

March 16, 2019
Tweet

More Decks by Nikita Galkin

Other Decks in Programming

Transcript

  1. Looking for
    the right tech stack
    for GraphQL application
    Nikita Galkin

    View Slide

  2. Nikita
    Galkin
    Love and Know:
    ▰ How to make developers and business happy
    ▰ Technical and process debt elimination
    Believe that:
    ▰ Any problem must be solved at the right level
    ▰ Software is easy. People are hard
    ▰ A problem should be highlighted, an idea should
    be "sold", a solution should be demonstrated
    Links:
    Site GitHub Twitter Facebook
    2

    View Slide

  3. GraphQL is
    an open source
    query language
    created by
    Facebook
    The specification
    published in June 2018

    View Slide

  4. What problems
    does GraphQL
    solve?

    View Slide

  5. Client
    Development is too
    expensive

    View Slide

  6. Ask for
    what you need,
    get exactly that

    View Slide

  7. Domain knowledge
    does not represent
    at a single place as
    source code

    View Slide

  8. By Dmytro Naumenko

    View Slide

  9. Describe
    what’s
    possible
    with a type
    system

    View Slide

  10. It is complicated to
    develop Server and
    Client in parallel

    View Slide

  11. View Slide

  12. GraphQL
    is awesome!

    View Slide

  13. GraphQL
    is awesome!

    View Slide

  14. But…
    with GraphQL
    Server Development
    becomes much harder

    View Slide

  15. My story:
    Node.js and GraphQL
    during
    1 year and 4 projects

    View Slide

  16. Honeymoon with GraphQL:
    ● Reading docs
    ● Exploring
    how to GraphQL
    ● Comparing Apollo,
    Prisma, Relay, etc
    ● Choosing IDE

    View Slide

  17. GraphiQL

    View Slide

  18. GraphQL Playground

    View Slide

  19. Insomnia

    View Slide

  20. GraphQL Schema Definition Language:
    ● A type has a name and can implement
    one or more interfaces
    ● A field has a name and a type
    ● The built-in scalar types are
    Int/Float/String/Boolean/ID
    ● Enum is a scalar value that has a
    specified set of possible values

    View Slide

  21. View Slide

  22. I love to look in
    the mirrors
    Worse than D.R.Y.,
    DUPLICATION at:
    ● Schema
    ● DB tables
    ● Endpoints
    Common solution:
    ● Schema generation

    View Slide

  23. GraphQL at Facebook by Adam D.I. Kramer

    View Slide

  24. View Slide

  25. {
    __schema {
    types {
    __typename
    name
    }
    }
    }
    Introspection
    query
    Class
    reflections
    JavaScript have not Reflection

    View Slide

  26. npm install:
    ● reflect-metadata
    ● typescript
    ● type-graphql
    ● any other useful
    decorators first
    packages

    View Slide

  27. import { Field, ID, ObjectType } from 'type-graphql';
    import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm';
    @Entity({ name: 'users' })
    @ObjectType()
    export class User {
    @PrimaryGeneratedColumn('uuid') @Field(type => ID) id: string;
    @Column() @Index({ unique: true }) @Field() email: string;
    @Column() passwordHash: string;
    @Column({ nullable: true }) @Field({ nullable: true }) firstName?: string;
    @Column({ nullable: true }) @Field({ nullable: true }) lastName?: string;
    @Field() get name () {
    return `${this.firstName} ${this.lastName}`;
    }
    }

    View Slide

  28. import { Ctx, Query, Resolver } from 'type-graphql';
    import { GraphQLContext } from '~/boundaries/graphql';
    import { UsersRepository } from '~/repositories';
    import { User } from '~/entities';
    @Resolver(type => User)
    export class UserResolver {
    @Query(type => User)
    async currentUser (
    @Ctx() context: GraphQLContext
    ): Promise {
    return UsersRepository.find(
    { where: { id: context.user.id } },
    );
    }
    }

    View Slide

  29. Documentation and
    examples:
    https://typegraphql.ml

    View Slide

  30. I have Big
    Latency, perhaps
    Reasons:
    ● Poor Performance
    ● Too many DB
    queries
    ● Client cache only
    Common solution:
    ● Dataloader

    View Slide

  31. Precomputed data
    You store data for resolvers
    in NoSQL DB with structure
    similar GraphQL schema.
    Limitations:
    ● You have data ownership

    View Slide

  32. We need data, but there
    are not decorators for
    such source type. For
    example:
    ● Elastic Search
    ● Data from external API
    ● etc
    I miss
    something...

    View Slide

  33. // class
    class User {
    constructor(name, surname) {
    this.name = name;
    this.surname = surname;
    }
    }
    // class instance
    new User('Bart', 'Simpson');
    // plain (literal) object ==============>
    const hero = {
    name: 'Gomer',
    surname: 'Simpson'
    };
    POM

    View Slide

  34. import { plainToClass } from 'class-transformer';
    fetch("users.json").then((users: Object[]) => {
    const realUsers = plainToClass(User, users);
    // now each user in realUsers is instance of User class
    });
    const hero = {
    name: 'Gomer',
    surname: 'Simpson'
    };
    hero instanceof User; // false

    View Slide

  35. https://github.com/typestack/class-transformer
    Serialize/Deserialize
    on steroids with decorators:
    ● @Type
    ● @Expose
    ● @Exclude
    ● Use discriminator for arrays!

    View Slide

  36. Reasons:
    ● SELECT all, because
    pagination and
    sorting implemented
    in the resolver
    ● SELECT * FROM ...
    ● JOIN is used
    I have Big
    Requests, Dear!

    View Slide

  37. Precomputed
    Materialized View

    View Slide

  38. Sorting, filtering and
    pagination
    should be implemented
    on Data Layer

    View Slide

  39. GraphQL Resolver function signature:
    fieldName(obj, args, context, info)
    ● obj: The object that contains the result
    returned from the resolver on the parent field
    ● args: An object with the arguments passed
    into the field in the query
    ● context: This is an object shared by all
    resolvers
    ● info: AST, state of resolving. Example

    View Slide

  40. import { GraphQLResolveInfo } from 'graphql';
    import graphqlFields from 'graphql-fields';
    import { Ctx, Info, Query, Resolver } from 'type-graphql';
    import { GraphQLContext } from '~/boundaries/graphql';
    import { UsersRepository } from '~/repositories';
    import { User } from '~/entities';
    @Resolver(type => User)
    export class UserResolver {
    @Query(type => User)
    async currentUser (
    @Ctx() context: GraphQLContext,
    @Info() info: GraphQLResolveInfo
    ): Promise {
    const fields = graphqlFields(info);
    return UsersRepository.find(
    { where: { id: context.user.id } },
    { select: Object.keys(fields) }
    );
    }
    }

    View Slide

  41. import graphqlFields from 'graphql-fields';
    // ...
    async currentUser (
    @Ctx() context: GraphQLContext,
    @Info() info: GraphQLResolveInfo
    ): Promise {
    const fields = graphqlFields(info);
    return UsersRepository.find(
    { where: { id: context.user.id } },
    { select: Object.keys(fields) }
    );
    }

    View Slide

  42. ● ACL
    ● Query Complexity
    We have to talk
    about our
    relationship...
    import { Authorized } from 'type-graphql';
    // ...
    @ObjectType()
    export class User {
    // ...
    @Authorized('Admin', 'CurrentUser')
    @Field()
    email: string;
    @Field(type => User,{ complexity: 20 })
    friends: User[];
    }

    View Slide

  43. Solutions:
    ● For versioning
    graphql-doctor
    ● For CI/CD
    eslint-plugin-graphql
    ● For development
    WebStorm IDE plugin
    Let's not change
    anything?

    View Slide

  44. View Slide

  45. View Slide

  46. Ideas:
    ● Have only one source of truth
    ● Don’t repeat yourself
    ● Use the right tools
    ● Solve problem at the right level

    View Slide

  47. 47
    THANKS!
    HAPPY CODING
    WITH GRAPHQL
    You can find me on Twitter as @galk_in
    Slides are available at speakerdeck.com/galkin
    or at my site galk.in

    View Slide