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

GraphQLでフロントエンドの複雑性とたたかう

narirou
September 03, 2019

 GraphQLでフロントエンドの複雑性とたたかう

narirou

September 03, 2019
Tweet

More Decks by narirou

Other Decks in Technology

Transcript

  1. 2019-09-03
    Bonfire Frontend #4
    Yahoo! JAPAN / GYAO!
    GraphQLͰϑϩϯτΤϯυͷෳࡶੑͱ͔ͨͨ͏

    View Slide

  2. Masanari Hamada
    @narirou
    ͓࢓ࣄ
    2015೥৽ଔೖࣾ
    GYAO! WEB ͷΞʔΩςΫνϟ࡮৽
    GYAO ಈըϓϨʔϠʔ࡮৽
    GYAO iOS SwiftԽ/ϦϑΝΫλϦϯά౳
    σβΠϯγεςϜ / JAMStack / WEBඪ४ ʹڵຯ͕͋Γ·͢
    ࣥච
    WEB+DB PRESS ͷϑϩϯτΤϯυ࿈ࡌهࣄͱͯ͠Storybookɺ
    HeadlessCMSͷهࣄΛࣥච

    View Slide

  3. GraphQL͕஀ੜͨ͠എܠͱ՝୊
    ෳࡶੑΛղܾ͢ΔΫϥΠΞϯταΠυͷ࢓૊Έ
    APENDIX

    View Slide

  4. GraphQL
    GraphQL͸FacebookʹΑΓ։ൃ͞ΕͨΦʔϓϯιʔεͷΫ
    ΤϦݴޠ
    2012೥ Facebookࣾ಺Ͱ։ൃ
    2015೥ ΦʔϓϯιʔεԽ
    ݱࡏ͸ Githubͷ graphql/graphql-spec ʹͯ൚༻తͳΫΤϦ
    ݴޠ࢓༷ͱͯ͠ࡦఆ͞Ε͍ͯΔ

    View Slide

  5. GraphQL͕ͳͥඞཁ͔

    View Slide

  6. 1. ΫϥΠΞϯταΠυͷෳࡶͳཁٻ
    2000೥ RESTful API (Roy Fielding)
    REST͸൚༻తʹ࡞ΒΕͨΤϯυϙΠϯτʹରͯ͠൚༻Խ͞ΕͨσʔλΛऔಘ͢Δ

    View Slide

  7. ୯७ͳΫΤϦͰ΋ෳ਺ճͷ௚ྻͳRESTApiϦΫΤετ͕ඞཁʹͳ͋Δ৔߹͕͋Δ
    औಘͨ͠σʔλʹ͸ෆཁͳ߲໨͕ଘࡏ͢Δ

    View Slide

  8. දࣔͷཁ݅͸ຊ࣭తʹΫϥΠΞϯτͷը໘࢓༷ʹ
    ґଘ͢Δ
    (ͦͯͦ͠Ε͸ɺසൟʹมߋ͞ΕΔ)
    ❖ ը໘ͷσβΠϯ͸มΘΔ..
    ❖ ද͍߲ࣔͨ͠໨΋มΘΔ..
    ❖ ಛघͳ৚݅ͰABςετ͍ͨ͠..
    ❖ σόΠεʹΑͬͯෳ਺ͷσʔλ͕ඞཁ..
    RESTͰͲ͏΍ͬͯରԠ͢Δʁ

    View Slide

  9. -> RESTfulͷݶք…
    ͢΂ͯͷΫϥΠΞϯτଆͷཁ݅Λຬͨ͢ʹ͸
    RESTfulͰ͸࠷దԽ͕ࠔ೉
    ֦ுੑ / ύϑΥʔϚϯε / ։ൃ଎౓ ͕٘ਜ਼ʹͳΔ

    View Slide

  10. query(userId: ID!) {
    history(userId: $userId) {
    videos {
    id
    title
    }
    }
    }
    ྫ͑͹ө૾ͷࢹௌཤྺͷྫ͸ɺGraphQLͰ͋Ε͹ɺҎԼͷΫΤϦͰ໨
    తͷσʔλ͕औಘͰ͖Δ

    View Slide

  11. 2. αʔϏεؒͷεΩʔϚ࿈ܞ
    ❖ ϚΠΫϩαʔϏεΞʔΩςΫνϟͰ͸ɺαʔϏεؒͷ࿈ܞ͕ѹ౗
    తʹ૿Ճ͢Δ
    ❖ ֤αʔϏεͰඞཁͳσʔλ߲໨͸໌ࣔతʹ͠ɺαʔϏεؒͷ࿈
    ܞΛ҆શʹߦ͏ඞཁੑ͕͋Δ

    View Slide

  12. ʮίϯϙʔωϯτʯ͝ͱʹඞཁͳσʔλ͸ҟͳΓɺ໌ࣔతʹ͢Δඞཁ͕͋Δ
    ֤ίϯϙʔωϯτͰඞཁͳσʔλΛએݴతʹهड़Ͱ͖Δ࢓૊Έ͕ͳ͍ͱε
    έʔϧ͠ͳ͍
    ΫϥΠΞϯταΠυͰ΋ಉ༷ͷ໰୊

    View Slide

  13. query Heros {
    heros(first: 10) {
    name
    }
    }
    {
    "heros": [
    { "name": "R2-D2" }
    ]
    }
    export function Users() {
    const { data } = useQuery(HeroNameQuery);
    return data.heros.map(hero => );
    }

    View Slide

  14. GraphQLΛ஌Δ

    View Slide

  15. type Post {
    id: String!
    title: String!
    publishedAt: DateTime!
    likes: Int! @default(value: 0)
    blog: Blog @relation(name: "Posts")
    }
    type Blog {
    id: String!
    name: String!
    description: String
    posts: [Post!]! @relation(name: "Posts")
    }
    GraphQL SDL (schema definition language)
    εΩʔϚઃܭͷهड़ݴޠΛSDLͱͯ͠൚༻తʹࡦఆ
    ܕͷఆٛͱͯ͠໌ࣔతͰཧղ͠΍͍͢

    View Slide

  16. Interface
    interface Post {
    id: ID!
    title: String!
    text: String!
    }
    ❖ ඪ४Ͱ࣋ͭܕ(Scalar Type)ʹ͸ɺString, Int ͳͲ
    ❖ ! ͸ non-nullable Λද͢

    View Slide

  17. Type
    ❖ implementsͰఆٛͨ͠interfaceܕΛදݱͰ͖Δ
    type BlogPost implements Post {
    id: ID!
    title: String!
    text: String!
    }

    View Slide

  18. Query
    ❖ $id ෦෼͕Ҿ਺ɺ࣮ࡍʹΫΤϦ࣌ʹม਺ͱͯ͠ೖྗ͢Δ
    query BrogPostQuery($id: ID!) {
    post(id: $id) {
    title
    }
    }
    {
    "data": {
    "post": {
    "title": "Learning GraphQL"
    }
    }
    }

    View Slide

  19. Fragment
    ❖ ܁Γฦ͕͠ଟ͘ग़ݱ͢ΔͳͲΫΤϦશମ͕ංେԽ͢Δ
    ❖ ࠶ར༻ՄೳͳΫΤϦͷҰ෦Λ੾Γग़ͯ͠දݱͰ͖Δ
    {
    leftComparison: hero(episode: EMPIRE) {
    ...comparisonFields
    }
    rightComparison: hero(episode: JEDI) {
    ...comparisonFields
    }
    }
    fragment comparisonFields on Character {
    name
    appearsIn
    friends {
    name
    }
    }

    View Slide

  20. Mutations
    ❖ σʔλͷॻ͖ࠐΈ͸mutationΫΤϦΛൃߦͯ͠ॲཧ͢Δ
    mutation CreateReviewForEpisode($ep: Episode!, $review:
    ReviewInput!) {
    createReview(episode: $ep, review: $review) {
    stars
    commentary
    }
    }

    View Slide

  21. ͜ΕҎ֎ʹ΋ɺ༷ʑͳఆ͕ٛ͋ΔͷͰҎԼΛࢀর
    https://graphql.org/learn/schema
    https://graphql.org/learn/queries
    Directives
    @skip @include ͳͲಛఆ৚݅ͰॲཧΛߦ͏͜ͱΛɺΫΤϦʹهड़Ͱ͖Δ
    UnionTypes
    ෳ਺ͷtypeΛ࣋ͬͨtypeΛఆٛ͢Δ

    View Slide

  22. APIυΩϡϝϯτͱPlayground

    View Slide

  23. ΠϯτϩεϖΫγϣϯ
    GraphQLαʔόʔ͸ɺࣗ਎ͷεΩʔϚఆٛΛެ։͢Δ࢓૊ΈΛඋ͑Δ
    ࣮ࡍʹΫΤϦΛͨͲͬͯΈΔͱɺ಺෦Ͱࢀর͍ͯ͠Δܕ৘ใ͕Θ͔Δ
    {
    __schema {
    types {
    name
    }
    }
    }
    {
    "data": {
    "__schema": {
    "types": [
    {
    "name": "ID"
    }
    ]
    }
    }
    }

    View Slide

  24. GUI (GraphiQL, GraphQL Playground)
    ❖ ӈଆͷϖΠϯ͔Βɺܕ৘ใΛӾཡ
    ❖ ࠨଆͷϖΠϯ͔Βɺ࣮ࡍʹΫΤϦΛ౤͛Δ͜ͱ͕Ͱ͖Δ
    ఆٛʹίϝϯτΛهड़͓ͯ͘͜͠ͱͰɺ։ൃ࣌ʹ͸PlaygroundΛ
    υΩϡϝϯςʔγϣϯͷ୅ସͱͯ͠ར༻Ͱ͖Δ

    View Slide

  25. ΫϥΠΞϯτͱͷ࿈ܞ
    Apollo Client, Relay…

    View Slide

  26. Apollo Client
    GraphQLͷ௨৴ॲཧΛΫϥΠΞϯτଆͰѻ͏ͨΊͷϥΠϒϥϦɻ
    ར༻ଆ͸ɺએݴతͳΫΤϦͷهड़Ͱجຊతͳ௨৴Λར༻Ͱ͖Δɻ
    ❖ঢ়ଶͷ؅ཧ
    ❖Ωϟογϡ؅ཧͷந৅Խ
    ❖௨৴ؒͷॲཧͷந৅Խ

    View Slide

  27. Apollo Client Λར༻͢Δ
    import ApolloClient from 'apollo-boost';
    import gql from 'graphql-tag';
    const client = new ApolloClient({
    uri: 'https://48p1r2roz4.sse.codesandbox.io',
    });
    client
    .query({
    query: gql`
    {
    rates(currency: "USD") {
    currency
    }
    }
    `
    })
    .then(result => console.log(result));

    View Slide

  28. View Slide

  29. ௨৴ؒͷॲཧͷந৅Խ (Apollo Link)
    ApolloLink͸ΫϥΠΞϯτଆͷ௨৴ͷந৅Խ૚ʹ౰ͨΔ෦෼Ͱ͋
    Γɺ؆қతͳϓϩΩγͱͯ͠ػೳ͢Δ
    expressͷϛυϧ΢ΣΞͷΑ͏ͳߏ੒ʹͳ͍ͬͯΔ
    ApolloClient͸ɺ͜ͷ࢓૊ΈͰϦΫΤετͷ࠷దԽΛߦ͏͜ͱͰɺൃ
    ੜ͢Δ༷ʑͳෳࡶੑΛճආ͍ͯ͠Δ

    View Slide

  30. ௨৴ؒͷॲཧͷந৅Խ (Apollo Link)
    ❖ apollo-link-http (جຊతͳ௨৴)
    ❖ apollo-link-batch-http (όονॲཧ)
    ❖ apollo-link-rest (REST APIΛGraphQLͷΑ͏ʹѻ͏ந৅Խ૚)
    ❖ …

    View Slide

  31. ΫϥΠΞϯτͷঢ়ଶΛ؅ཧ͢Δ
    apollo-link-state ͸ɺϩʔΧϧͷঢ়ଶΛ؅ཧ͢ΔͨΊͷApolloLink
    ❖ ͜ͷߏ੒͸Reduxʹࣅ͍ͯΔ
    ❖ ApolloͰ؅ཧ͢Δσʔλ
    (ApolloCache) ΛΫϥΠΞϯτ
    ଆͷ།ҰͷσʔλετΞͷΑ
    ͏ʹ΋ѻ͏͜ͱ͕Ͱ͖Δ

    View Slide

  32. import React from "react";
    import { useQuery } from "@apollo/react-hooks";
    import gql from "graphql-tag";
    import Link from "./Link";
    const GET_VISIBILITY_FILTER = gql`
    {
    visibilityFilter @client
    }
    `;
    function FilterLink({ filter, children }) {
    const { data, client } = useQuery(GET_VISIBILITY_FILTER);
    return (
    onClick={() => client.writeData({ data: { visibilityFilter: filter } })
    active={data.visibilityFilter === filter}
    >
    {children}

    )
    }

    View Slide

  33. ίʔυͷࣗಈੜ੒ͱ࠷దԽ

    View Slide

  34. GraphQL SDL͸൚༻తʹࡦఆ͞Ε͓ͯΓɺ͜ͷఆ͔ٛΒ༷ʑͳݴޠ
    Ͱ׆༻Ͱ͖ΔΑ͏ม׵Ͱ͖Δ

    View Slide

  35. TypeScriptͱͷ࿈ܞ
    ❖ @graphql-codegen/typescript
    ❖ @graphql-codegen/typescript-operations
    ❖ @graphql-codegen/typescript-react-apollo
    graphql-codegenɺapollo-tooling ʹΑͬͯɺΫΤϦ͔ΒTypeScript
    ༻ͷίʔυΛग़ྗ͢Δ

    View Slide

  36. {
    posts {
    title
    text
    labels {
    name
    }
    thumbnail {
    width
    height
    url
    }
    }
    }
    export type BlogPostsQuery = {
    posts: Maybe<
    Array<
    Pick<
    BlogPost,
    | "title"
    | "text"
    > & {
    labels: Maybethumbnail: Pick}
    >
    >;
    };
    ྫ͑͹ graphql-codegen ͰࠨͷΑ͏ͳΫΤϦΛม׵͢Δͱɺ
    ӈهͷΑ͏ͳtypes͕ੜ੒͞ΕΔ

    View Slide

  37. Reactͱͷ࿈ܞ
    @apollo/react-hooksͷΧελϜϑοΫuseQueryΛར༻ͯ͠ɺ
    GraphQLͷϦΫΤετΛߦ͏

    View Slide

  38. const GreetingQuery = gql`
    query getGreeting($language: String!) {
    greeting(language: $language) {
    message
    }
    }
    `;
    function Hello() {
    const { loading, error, data } = useQuery(GreetingQuery, {
    variables: { language: 'english' },
    });
    if (loading) return Loading ...;
    return Hello {data.greeting.message}!;
    }

    View Slide

  39. export function useGreetingQuery(
    baseOptions?: ReactApolloHooks.QueryHookOptions<
    GetGreetingQuery,
    GetGreetingQueryVariables
    >
    ) {
    return ReactApolloHooks.useQuery<
    GetGreetingQuery,
    GetGreetingQueryVariables
    >(StoreTitlesDocument, baseOptions);
    }
    export type GetGreetingQueryHookResult = ReturnTypeΫΤϦ(CustomHook)ͷࣗಈੜ੒
    ͞Βʹɺ@apollo/react-hooks ͱͷ࿈ܞ͢ΔͱɺΫΤϦ͔Β
    ReactHooks༻ͷΧελϜϑοΫΛࣗಈੜ੒͠ɺܕ҆શͳঢ়ଶͰΫΤ
    ϦΛར༻Ͱ͖Δɻ

    View Slide

  40. {
    "scripts": {
    "schema": “node ./script/graphql-codegen.js"
    }
    }
    ͜ΕΒͷੜ੒͸ίϚϯυ͔Β༰қʹੜ੒͢ΔΑ͏ʹ͓ͯ͘͠ͱGood

    View Slide

  41. ՝୊

    View Slide

  42. query Heros {
    messages(first: 99999999) {
    title
    messages(first: 99999999) {
    title
    messages(first: 99999999) {
    title
    }
    }
    }
    }
    1. ύϑΥʔϚϯεΫϦςΟΧϧͳΫΤϦ͕ൃߦ͞ΕΔ
    ެ։͢ΔGraphQLαʔόʔ͸ɺηΩϡϦςΟΛҙࣝ͢Δඞཁ͕͋Δ
    ྫ͑͹ɺҎԼͷΑ͏ͳΫΤϦ͸ڐ༰ͨ͘͠ͳ͍…

    View Slide

  43. ❖ αΠζΛ੍ݶ͢Δ
    ❖ ωετͷ੍ݶ͢Δ
    graphql-depth-limit ͰωετΛ੍ݶ͢Δ
    ❖ ෳࡶ౓Λܭࢉ੍͠ݶ͢Δ
    ❖ ΫΤϦΛϗϫΠτϦετొ࿥͢Δ (Persisted Queries)
    ΫΤϦΛࣄલʹhashԽ͓͖ͯ͠ɺ௨৴࣌΋hash஋Λ༻͍ͯߦ͏
    ڐՄ͞ΕͨhashͷΫΤϦͷΈڐ༰ͯ͠ϨεϙϯεΛฦ͢
    1. ύϑΥʔϚϯεΫϦςΟΧϧͳΫΤϦ͕ൃߦ͞ΕΔ
    खॱ͕ෳࡶͳͨΊɺΑΓΑ͍ղܾࡦ͕΄͍͠ͱ͜Ζ..

    View Slide

  44. 2. දࣔཁૉͰར༻͢Δܕʹมܗ͠ʹ͍͘
    ෳࡶͳΫΤϦʹͳΔͱɺදࣔ༻ͷܕͱͯ͠ѻ͏ͨΊͷม׵͕ඞཁ
    ࣗಈੜ੒͞Εͨڊେͳܕ৘ใ͔Βͷม׵ͱͳΔͷͰɺܕΛҡ࣋ͯ͠
    ม׵͢Δ͜ͱ͕೉͍͠
    ts-toolbelt ͳͲΛར༻ͯ͠ɺܕͷҰ෦Λมߋ͢Δ͜ͱͰରԠ͍ͯ͠Δ

    View Slide

  45. ·ͱΊ

    View Slide

  46. ❖ GraphQL͸ΫϥΠΞϯτͷෳࡶͳཁ݅ʹਝ଎ʹରԠ͢ΔͨΊͷɺ
    1ͭͷղܾखஈ
    ίʔυͷࣗಈੜ੒
    ωοτϫʔΫ૚ͷࣗಈ࠷దԽ
    ❖ औಘ͢ΔσʔλΛએݴతʹهड़͠ɺܕ҆શʹ։ൃͰ͖ΔੈքΛ໨
    ࢦ͍ͯ͠Δ
    ❖ ෛՙతͳηΩϡϦςΟͷ՝୊΍ɺN+1໰୊౳ɺGraphQLಛ༗ͷෳ
    ࡶੑ͕͋Γɺ͜Ε͔Βͷ՝୊Ͱ͋Δ
    ·ͱΊ

    View Slide

  47. ·ͱΊ
    ΫϥΠΞϯταΠυ͸ɺෳࡶͳ࢓༷มߋɾϢʔβʔૢ࡞ʹΑΔมԽͳͲɺΞϓ
    ϦέʔγϣϯͷதͰ΋ͬͱ΋ෳࡶͳ෭࡞༻͕ൃੜ͢Δ৔ॴͰ΋͋Γ·͢ɻ
    GraphQL, Falcor, gRPC…
    REST͕ൃ໌͞Ε͔ͯΒ਺10೥ɺ՝୊Λײ͍ͯ͡Δ֤͔ࣾΒAPIͷύϥμΠϜɾ
    γϑτΛ༧ײͤ͞Δٕज़͕ग़࢝Ί͍ͯ·͕͢ɺGraphQL͸ͦͷைྲྀͷҰ୺Λ୲
    ͏ٕज़ͷ1ͭͰ͢ɻ
    ͜͏ͨ͠ෳࡶੑͷ໰୊ͱɺͦͷղܾҊͱͯ͠ߟ͑ΒΕ͍ͯΔഎܠΛ஌ͬͯɺΑ
    ΓΑ͍ٕज़Ͱ͜Ε͔ΒͷWEB։ൃΛ৐Γӽ͍͖͑ͯ·͠ΐ͏ɻ

    View Slide

  48. ΑΓਂ͘஌Δʹ͸ (ࢀߟจݙ)
    ❖ GraphQL, ApolloͷެࣜυΩϡϝϯτ
    ❖ ΫΤϦͷجૅΛ஌Δ: [Queries and Mutations](https://graphql.org/learn/queries/)
    ❖ എܠΛ஌Δ: [Github Blog | The GitHub GraphQL API](https://githubengineering.com/the-
    github-graphql-api/)
    ❖ ApolloLinkΛ஌Δ: [Apollo Link Overview](https://www.apollographql.com/docs/link/
    overview/)
    ❖ ϕετϓϥΫςΟεΛ஌Δ: [GraphQL Best Practice](https://graphql.org/learn/best-practices/)
    ❖ ੍ݶΛ͔͚Δ: [HOW TO SECURE A GRAPHQL API (THE COMPLETE VULNERABILITY
    CHECKLIST)](https://leapgraph.com/graphql-api-security)
    ❖ ੍ݶΛ͔͚Δ: [GraphQLͱPsersisted Query by @Quramy](https://qiita.com/Quramy/items/
    b3943a0c27f3ade2c57d)

    View Slide