Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

GraphQL͕ͳͥඞཁ͔

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

GraphQLΛ஌Δ

Slide 15

Slide 15 text

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ͱͯ͠൚༻తʹࡦఆ ܕͷఆٛͱͯ͠໌ࣔతͰཧղ͠΍͍͢

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

APIυΩϡϝϯτͱPlayground

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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));

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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 ( client.writeData({ data: { visibilityFilter: filter } }) active={data.visibilityFilter === filter} > {children} ) }

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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}!

; }

Slide 39

Slide 39 text

export function useGreetingQuery( baseOptions?: ReactApolloHooks.QueryHookOptions< GetGreetingQuery, GetGreetingQueryVariables > ) { return ReactApolloHooks.useQuery< GetGreetingQuery, GetGreetingQueryVariables >(StoreTitlesDocument, baseOptions); } export type GetGreetingQueryHookResult = ReturnType

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

՝୊

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

·ͱΊ

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

ΑΓਂ͘஌Δʹ͸ (ࢀߟจݙ) ❖ 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)