Slide 1

Slide 1 text

ۜ࠲3BJMT (SBQI2-ͷߴ଎ಓ࿏

Slide 2

Slide 2 text

(SBQI2-ͱ͸

Slide 3

Slide 3 text

(SBQI2-͸'BDFCPPLʹΑͬͯ࡞ΒΕͨ w ೥'BDFCPPLʹΑͬͯ։ൃ։࢝ w χϡʔεϑΟʔυͷ಺༰Λදݱ͢ΔͨΊʹߟҊ w ೥(SBQI2-ൃදʢ3FMBZ΋ಉ೥ʹൃදʣ w ೥ςΫχΧϧϓϨϏϡʔΛ୤͢Δ w (JU)VC͕(SBQI2-"1*Λఏڙ։࢝ w ೥(SBQI2-'PVOEBUJPOʹҠ؅͞Εͨ

Slide 4

Slide 4 text

(SBQI2-͸8FC"1*ͷͨΊͷΫΤϦݴޠ औಘ͞ΕΔσʔλ͕ΫΤϦͱҰக͢Δ query { posts { title } } { "posts": [ { "title": "Hello World" }, { "title": "Hi" } ] }

Slide 5

Slide 5 text

ΫΤϦݴޠ͕ඞཁͳཧ༝ (SBQI2-͕3&45ʹରͯ࣋ͭ͠Ξυόϯςʔδ w ΦʔόʔϑΣονϯάΛ๷͛Δ w ϦΫΤετ਺ΛݮΒͤΔ w ΫϥΠΞϯτͷมԽʹରͯ͠ॊೈ

Slide 6

Slide 6 text

(SBQI2-Ͱ͸ΦʔόʔϑΣονϯάΛ๷͛Δ ඞཁҎ্ͷσʔλΛऔಘͯ͠͠·͏͜ͱΛΦʔόʔϑΣονϯάͱ͍͏ { "posts": [ { "title": "Hello World", "body": "Lorem ipsum", "authorId": "1" }, { "title": "Hi", "body": "Hi there.", "authorId": "2" } ] } { "posts": [ { "title": "Hello World" }, { "title": "Hi" } ] }

Slide 7

Slide 7 text

(SBQI2-Ͱ͸ΦʔόʔϑΣονϯάΛ๷͛Δ w ΫϥΠΞϯτ͕ඞཁͳσʔλΛཁٻ͢ΔͨΊΦʔόʔϑΣονϯά͕ى͖ͳ͍ w ΦʔόʔϑΣονϯά͕๷͕ΕΔ͜ͱͰ w సૹྔΛখ͘͞Ͱ͖Δ w αʔόʔαΠυ΋ϦιʔεΛઅ໿Ͱ͖Δ w ΞϯμʔϑΣονϯά͸όά😢

Slide 8

Slide 8 text

(SBQI2-Ͱ͸ϦΫΤετ਺ΛݮΒͤΔ ґଘؔ܎ͷ͋ΔϦιʔεΛҰ౓ͰऔಘͰ͖Δ GET /posts GET /author/1 GET /author/2 query { posts { title author { name } } }

Slide 9

Slide 9 text

(SBQI2-Ͱ͸ϦΫΤετ਺ΛݮΒͤΔ w ͻͱͭͷը໘ʹඞཁͳσʔλΛϦΫΤετͰऔಘͰ͖Δͷ͕ཧ૝ w ϦΫΤετʹ͔͔Δ͕࣌ؒ355 3PVOE5SJQ5JNF w ฒྻʹϦΫΤετͰ͖Ε͹ෳ਺ͷϦΫΤετ͕͋ͬͯ΋355ͰࡁΉ͕ w ϦΫΤετؒʹґଘؔ܎͕͋Δͱ/355ʹͳΔ w 3&45Ͱ͸࣮ݱ͕ࠔ೉ w ৔߹ʹΑͬͯ͸3&45෩ͷԿ͔ʹͳ͍ͬͯ͘😢

Slide 10

Slide 10 text

(SBQI2-͸ΫϥΠΞϯτͷมԽʹॊೈ "1*ʹྺ࢙తܦҢ͕஝ੵ͍ͯ͘͜͠ͱΛ๷͛Δ { "title": "Hello World", "body": "Lorem ipsum", "tags": ["essay", "blog"], // ࠓ͸࢖͍ͬͯͳ͍͕ޓ׵ੑͷͨΊʹ࢒͢ "tag_objects": [ { "name": "essay", "id": "1" }, { "name": "blog", "id": "2" } ] }

Slide 11

Slide 11 text

(SBQI2-͸ΫϥΠΞϯτͷมԽʹॊೈ w ͻͱͭͷը໘ʹඞཁͳσʔλΛϦΫΤετͰऔಘͰ͖Δͷ͕ཧ૝ͱ͢Δͱ w ը໘ͷදࣔཁૉΛม͑Δ౓ʹ"1*Λม͑Δͷ͸ͭΒ͍ w ͢Ͱʹ࢖͍ͬͯͳ͍ϑΟʔϧυΛޓ׵ੑͷͨΊʹ࢒ͨ͠Γ͢Δ w 8FCϑϩϯτΤϯυ͚ͩͩͱ؇࿨͞ΕΔ w ωΠςΟϒΞϓϦ͸ݹ͍όʔδϣϯ͕࢒Γଓ͚Δ৔߹͕ଟ͍

Slide 12

Slide 12 text

(SBQI2-ͱ͸ 8FC"1*ͷͨΊͷΫΤϦݴޠ w ݱ୅తͳΫϥΠΞϯταΠυͷ։ൃʹదԠ͍ͯ͠Δ w 3&45తͳΞϓϩʔνͰ͸ղܾ͠ʹ͍͘՝୊Λղܾ͢Δ w ΦʔόʔϑΣονϯάΛ๷͛Δ w ϦΫΤετ਺ΛݮΒͤΔ w ΫϥΠΞϯτͷมԽʹରͯ͠ॊೈ w ͍͔ʹ΋Αͦ͞͏Ͱ͢Ͷʂ

Slide 13

Slide 13 text

(SBQI2-ͷجຊ

Slide 14

Slide 14 text

(SBQI2-ͷͭͷΦϖϨʔγϣϯ w 2VFSZ w Ϧιʔεͷऔಘɻ(&5ʹ૬౰ w .VUBUJPO w Ϧιʔεͷมߋɻ1045165%&-&5&ʹ૬౰ w 4VCTDSJQUJPO w Ϧιʔεͷߪಡɻ8FC4PDLFUͳͲΛ࢖͏ɻࠓճ͸ׂѪ

Slide 15

Slide 15 text

ΦϖϨʔγϣϯͷॻࣜ লུͰ͖Δ෦෼΋͋Δ query { post(id: "1") { title } } 
 query GetPost { post(id: "1") { title } } 
 query GetPost($id: ID!) { post(id: $id) { title } }

Slide 16

Slide 16 text

ΦϖϨʔγϣϯͷॻࣜ w RVFSZNVUBUJPOTVCTDSJQUJPO w ΦϖϨʔγϣϯ໊ w ม਺ w ϑΟʔϧυͷબ୒ w ύϥϝʔλΛऔΕΔ query GetPost($id: ID!) { post(id: $id) { title } }

Slide 17

Slide 17 text

(SBQI2-ͷεΩʔϚ 4%- 4DIFNB%F fi OJUJPO-BOHVBHF type Query { # ... } type Mutation { # ... } schema { query: Query mutation: Mutation }

Slide 18

Slide 18 text

(SBQI2-ͷܕ w εΧϥܕ w /PO/VMMܕ w Ϧετܕ w ྻڍܕ 
 w ΦϒδΣΫτܕ w Πϯϓοτܕ w ϢχΦϯܕ w ΠϯλʔϑΣʔε

Slide 19

Slide 19 text

εΧϥܕ w *OUŠූ߸෇͖Ϗοτ੔਺ w 'MPBUŠഒਫ਼౓ුಈখ਺఺਺ w 4USJOHŠ65'จࣈྻɻೋॏҾ༻ූͰғ͏ w #PPMFBOŠਅِ஋ɻUSVFGBMTF w *%ŠϢχʔΫͳࣝผࢠɻ࣮ଶ͸จࣈྻ w ಠࣗʹఆٛ͢Δ͜ͱ΋͋Δ

Slide 20

Slide 20 text

/PO/VMMܕ w (SBQI2-ͷܕ͸σϑΥϧτͰOVMM஋Λڐ༰͢Δ w OVMM஋͕ೖΒͳ͍͜ͱΛ໌֬ʹ͢Δͷ͕/PO/VMMܕ w Λޙஔ͢Δͱ/PO/VMMܕʹͳΔ String # null஋Λڐ༰͢Δ String! # null஋Λڐ༰͠ͳ͍

Slide 21

Slide 21 text

Ϧετܕ w εΫΤΞϒϥέοτͰғ͏ w /PO/VMMܕͱͷ૊Έ߹Θͤʹ஫ҙ [Post] [Post]! [Post!] [Post!]!

Slide 22

Slide 22 text

ྻڍܕ enum Order { ASC DESC } type Query { posts(order: Order = DESC): [Post!]! }

Slide 23

Slide 23 text

ΦϒδΣΫτܕ type Author { name: String! } type Post { title: String! author: Author! } type Query { posts: [Post!]! }

Slide 24

Slide 24 text

Πϯϓοτܕ w ύϥϝʔλʹΦϒδΣΫτܕ͸࢖͑ͳ͍ input CreatePostInput { title: String! body: String! } type Mutation { createPost(input: CreatePostInput!): Post! }

Slide 25

Slide 25 text

ϢχΦϯܕ type Comment { text: String! } type Trackback { title: String! url: String! } union Feedback = Comment | Trackback type Post { title: String! feedbacks: [Feedback!]! }

Slide 26

Slide 26 text

ΠϯλʔϑΣʔε interface Publication { title: String! body: String! } type Page implements Publication { title: String! body: String! } type Post implements Publication { title: String! body: String! comments: [Comment!]! }

Slide 27

Slide 27 text

σΟϨΫςΟϒ w εΩʔϚ΍ΦϖϨʔγϣϯʹϝλσʔλΛ͚ͭΒΕΔ directive @deprecated( reason: String = "No longer supported” ) on FIELD_DEFINITION | ENUM_VALUE type Query { posts: [Post!]! @deprecated }

Slide 28

Slide 28 text

(SBQI2-ͷجຊ w 2VFSZ.VUBUJPO4VCTDSJQUJPO͕͋Δ w ܕ͕͋Δ w εΩʔϚ͕ॻ͚Δ w ࢓༷͕ఆΊΒΕ͍ͯΔ w IUUQTTQFDHSBQIRMPSH0DUPCFS

Slide 29

Slide 29 text

Τϥʔ͸ϨεϙϯεͷFSSPSTͰฦ͢ ΤϥʔͷϑΥʔϚοτ͸࢓༷ͰఆΊΒΕ͍ͯΔ { "data": null, "errors": [ { "message": "body could not be fetched", "locations": [ { "line": 4, "column": 4 } ], "path": ["post", "body"] } ] }

Slide 30

Slide 30 text

(SBQI2-PWFS)551 HJUIVCDPNHSBQIRMHSBQIRMPWFSIUUQ w (SBQI2-"1*Λ)551Ͱఏڙ͢Δඪ४తͳ࢓༷͕ࡦఆத w ୯ҰͷΤϯυϙΠϯτʢయܕతʹ͸/graphqlʣͰ"1*Λఏڙ w GET΋͘͠͸POST { "query": "", "operationName": "", "variables": {} }

Slide 31

Slide 31 text

(SBQI2-ͷઃܭ

Slide 32

Slide 32 text

εΩʔϚઃܭ w ΞϓϦέʔγϣϯͷυϝΠϯʹ߹Θͤͨઃܭ͕ඞཁ w 3&45Ͱ͸Ϧιʔεʹରͯ͠$36%ૢ࡞Λఆٛ͢Δͷ͕جຊ w (SBQI2-Ͱ΋ͦΕ͸ಉ͚ͩ͡Ͳɺ೉͘͠ײ͡Δͱࢥ͏ w ࢓༷ͱͯ͠ఆٛ͞Ε͍ͯΔ΋ͷͰ͸ͳ͍͕ఆੴ͕͋Δ w ఆੴʹै͏ͱΫϥΠΞϯτʹͱͬͯ౎߹͕͍͍

Slide 33

Slide 33 text

Ϧιʔεͷൃݟ w Ϧιʔεͷൃݟ͕ελʔτ஍఺ w 3&45ͱಉ͡ w Ϧιʔε͸ΦϒδΣΫτܕͰදݱ w αʔόʔͷ಺෦࣮૷ͱ෼͚ͯߟ͑Δ w υϝΠϯϞσϧʹै͏ type Blog { id: ID! name: String! } type Post { id: ID! title: String! body: String! }

Slide 34

Slide 34 text

άϥϑߏ଄Λ࡞Δ ؔ࿈͢ΔϦιʔεΛϑΟʔϧυͰḷΕΔΑ͏ʹ͢Δ type Author { id: ID! name: String! } type Post { id: ID! title: String! authorId: ID! } type Author { id: ID! name: String! } type Post { id: ID! title: String! author: Author! }

Slide 35

Slide 35 text

άϥϑߏ଄Λ࡞Δ ؔ࿈͢ΔϦιʔεΛϑΟʔϧυͰḷΕΔΑ͏ʹ͢Δ type Query { posts( blogId: ID!, page: Int! ): [Post!]! } type Blog { posts(page: Int!): [Post!]! } type Query { blog(id: ID!): Blog! }

Slide 36

Slide 36 text

(SBQI2-ͷػೳΛ׆͔͢ w ྻڍܕ͕࢖͑Δͱ͜ΖͰ͸ੵۃతʹ࢖͏ w ΠϯλʔϑΣʔε΍ϢχΦϯܕ͕͏·͘࢖͑Δͱ͜Ζ͕͋Ε͹࢖͏ w /PO/VMMܕʹ͢΂͖ͱ͜ΖΛܾΊΔ

Slide 37

Slide 37 text

ΠϯλʔϑΣʔεΛ࢖ͬͨઃܭ 6($αΠτͰϢʔβʔΛෳ਺ͷܕͰදݱͨ͠ࣄྫ w ΞΫηε͖͍ͯͯ͠Δਓ͸7JTJUPSܕ w ౤ߘऀ͸6TFSܕ w ͲͪΒ΋"VUIPSΠϯλʔϑΣʔεΛ࣮૷ w 8PSLܕͷBVUIPSϑΟʔϧυ͸"VUIPSΛฦ͢ w ࣗ෼ͷ࡞඼ͳΒ7JTJUPSܕʹͳ͍ͬͯΔ

Slide 38

Slide 38 text

/PO/VMMܕΛͲΕ͘Β͍࢖͏΂͖͔ ;ͨͭͷελϯε͕͋Δ w ՄೳͳݶΓ/PO/VMMܕΛ࢖͏ w υϝΠϯϞσϧʹ߹Θͤͯ/PO/VMMܕΛͪΌΜͱ࢖͏ w OVMMΛڐ͢ͷ͸υϝΠϯϞσϧ্OVMM͕ҙຯΛ࣋ͭ৔߹͚ͩ w ཁॴཁॴͰOVMMΛڐ༰͢Δ w ෼ࢄγεςϜͷҰ෦͕ো֐Λى͍ͯ͜͠Δͱ͖ʹඋ͑Δ w શମΛΤϥʔʹ͢ΔΑΓҰ෦ΛOVMMʹͯ͠ฦ͢

Slide 39

Slide 39 text

7JFXFS (SBQI2-ʹΞΫηε͖ͯͨ͠ར༻ऀΛࢦ͢γϣʔτΧοτ w ༻ҙ͓ͯ͘͠ͱศར w ΫϥΠΞϯτϥΠϒϥϦʹΑͬͯ͸ w Query.viewerΛಛผѻ͍͢Δ type Viewer { name: String! } type Query { viewer: Viewer }

Slide 40

Slide 40 text

/PEFΠϯλʔϑΣʔε ࠶औಘՄೳͳϦιʔε w JEͰࣝผՄೳͰ͋Δ͜ͱΛظ଴ w άϩʔόϧʹҰҙ w *Eͷ஋ͰΫΤϦͰ͖Δ w ΫϥΠΞϯτϥΠϒϥϦʹΑͬͯ͸ w JEΛ࢖ͬͯΩϟογϡΛਖ਼نԽ͢Δ interface Node { id: ID! } type Query { node(id: ID!): Node }

Slide 41

Slide 41 text

࠶औಘ͕ͳͥॏཁͳͷ͔ ҰཡͱύʔϚϦϯΫ w ҰཡͰ͸λΠτϧ͚ͩΛදࣔ w ύʔϚϦϯΫͰ͸ຊจ΋දࣔ w JE͕͋Ε͹࠶औಘͰ͖Δ query GetPostList { posts { id title } } query GetPost($id: ID!) { post(id: $id) { id title body } }

Slide 42

Slide 42 text

࠶औಘ͕ͳͥॏཁͳͷ͔ ϖʔδωʔγϣϯ w ϖʔδ໨Ҏ߱Λऔಘ͢Δͱ͖ type Blog { id: ID! posts(page: Int!): [Post!]! } query { blog(id: "1") { id posts(page: 1) { id } } }

Slide 43

Slide 43 text

/PEFΠϯλʔϑΣʔε ࠶औಘՄೳͳϦιʔεΛҰൠԽͨ͠΋ͷ w 3FMBZ༝དྷ w ύʔϚϦϯΫΛ࣋ͭΑ͏ͳϦιʔε w JEͷ஋͸యܕతʹ͸ w CBTF ܕ໊ϓϥΠϚϦΩʔ w αʔόʔͰ͸ܕ໊ͰॲཧΛ෼͚Δ w ΫϥΠΞϯτ͸PQBRVFʹѻ͏ interface Node { id: ID! } type Post implements Node { id: ID! }

Slide 44

Slide 44 text

$POOFDUJPO ϖʔδωʔγϣϯͷந৅Խ w 3FMBZ༝དྷ w ΧʔιϧΛ࢖ͬͨϖʔδωʔγϣϯ w ΫϥΠΞϯτϥΠϒϥϦʹΑͬͯ͸ w ࣗಈతʹϖʔδωʔγϣϯͰ͖Δ type PageInfo { hasNextPage: Boolean! hasPreviousPage: Boolean! startCursor: String endCursor: String } type PostEdge { cursor: String! node: Post! } type PostConnection { pageInfo: PageInfo! edges: [PostEdge!]! } type Blog { posts(first: Int!, after: String): PostConnection! }

Slide 45

Slide 45 text

ϖʔδωʔγϣϯ w جຊ͸Χʔιϧϕʔεͷϖʔδωʔγϣϯ w ϖʔδωʔγϣϯ͢ΔϑΟʔϧυΛ࣋ͭΦϒδΣΫτ͕࠶औಘՄೳ͔͕ॏཁ w 2VFSZɺ7JFXFSɺ/PEF w ͳΜͰ΋ϖʔδωʔγϣϯ͠ͳ͍͍ͯ͘ w ཁૉ͕ݸఔ౓ʹऩ·Δͱܾ·͍ͬͯͨΒϦετܕΛબͿ

Slide 46

Slide 46 text

3FMBZͷ(SBQI2-4FSWFS4QFDJGJDBUJPO $POWFOUJPOPWFS$PO fi HVSBUJPO w 3FMBZ͸'BDFCPPL੡ͷ(SBQI2-ΫϥΠΞϯτϥΠϒϥϦ w αʔόʔʹ௥Ճͷ࢓༷Λཁٻ͢Δ w ΦϒδΣΫτͷ࠶औಘŠ/PEF w ϖʔδωʔγϣϯŠ$POOFDUJPO w 3FMBZΛ࢖Θͳ͍ͳΒै͏ඞཁ͸ͳ͍͕ɺ฿͓͍ͬͯͯଛ͸ͳ͍ w ͍ͣΕ΋Ұൠతͳ՝୊ͳͷͰ

Slide 47

Slide 47 text

.VUBUJPO͸Ϧιʔεͷ$6%͔Β͸͡ΊΔ w DSFBUF3FTPVSDF w VQEBUF3FTPVSDF w EFMFUF3FTPVSDF w ҙຯ͝ͱʹ෼ׂͯ͠΋͍͍ w େ͖͘ͳΓ͗͢ͳ͍Α͏ʹ type Mutation { createPost( input: PostInput!): Post! updatePost( id: ID!, input: PostInput!): Post! deletePost(id: ID!): ID! createDraftPost( input: PostInput!): Post! publishPost(id: ID!): Post! }

Slide 48

Slide 48 text

.VUBUJPOͷύϥϝʔλͱ໭Γ஋ w ύϥϝʔλ͸ΠϯϓοτܕΛ࢖͏ w ࣅͨߏ଄ʹͳΔͳΒڞ༗͢Δ w ฦΓ஋͸/PEF͔*%Λ࢖͏ w DSFBUFͱVQEBUFͰ͸/PEFΛฦ͢ w EFMFUFͰ͸*%Λฦ͢ input PostInput { title: String! body: String! } type Mutation { createPost( input: PostInput!): Post! updatePost( id: ID!, input: PostInput!): Post! deletePost(id: ID!): ID! }

Slide 49

Slide 49 text

(SBQI2-ͷεΩʔϚઃܭ w ઌਓͷ஌ܙʹֶͿ w ఆੴʹै͏ w (JU)VCͷ(SBQI2-"1*ͳͲΛࢀߟʹ͢Δ w IUUQTHJUIVCDPN4IPQJGZHSBQIRMEFTJHOUVUPSJBM w ࠷ऴతʹ͸໨తΛୡ੒Ͱ͖Δ͔͕Ұ൪ॏཁ w ΫϥΠΞϯτʹͱͬͯ౎߹ͷ͍͍"1*͕͍͍"1*

Slide 50

Slide 50 text

$PEFGJSTU͔4DIFNBGJSTU͔

Slide 51

Slide 51 text

ίʔυϑΝʔετͱεΩʔϚϑΝʔετ (SBQI2-εΩʔϚͷ4PVSDFPG5SVUI͕Ͳ͔͜ w (SBQI2-"1*Λ࡞Δͱ͖ʹ࠷ॳʹ൑அ͢Δ͜ͱ w ϥΠϒϥϦʹΑͬͯҧ͏ w ίʔυʹΑͬͯεΩʔϚ͕ܾ·ΔͳΒίʔυϑΝʔετ w HSBQIRMSVCZ͸جຊతʹ͸ͬͪ͜ w εΩʔϚΛ࡞ͬͯͦΕʹ߹ΘͤͯίʔυΛॻ͘ͳΒεΩʔϚϑΝʔετ

Slide 52

Slide 52 text

ίʔυϑΝʔετͷ͍͍ͱ͜Ζ w ίʔυͱεΩʔϚͷରԠ͕औΓ΍͍͢ w ϓϩάϥϛϯάݴޠͷػೳΛ׆͔͠΍͍͢ w ίʔυͷ࠶ར༻ w ϞδϡʔϧԽ

Slide 53

Slide 53 text

εΩʔϚϑΝʔετͷ͍͍ͱ͜Ζ w εΩʔϚத৺ʹͳΔ w εΩʔϚʹ͍ͭͯٞ࿦͠΍͍͢ w ҙਤͤͣඇޓ׵ͳมߋΛߦ͏ͷΛ๷͛Δ

Slide 54

Slide 54 text

ίʔυϑΝʔετ͔εΩʔϚϑΝʔετ͔ ݁ہͲͪΒ͕͍͍ͷ͔ w εΩʔϚϑΝʔετͷํ͕ࣗવͳϑϩʔͰ͸͋Δ w εΩʔϚϑΝʔετ͕ྲྀߦ͕ͬͨίʔυϑΝʔετ΁ͷ༳Γ໭͕͋͠Δ w ͓͢͢Ί͸ w εΩʔϚ͔Βίʔυੜ੒͢ΔʢHRMHFOͳͲʣ w ίʔυ͔ΒεΩʔϚΛੜ੒ͯ͠ίϛοτ͢Δ w ͍ͣΕʹͯ͠΋εΩʔϚʹ͍ͭͯαʔόʔɾΫϥΠΞϯτؒͷٞ࿦͕ॏཁ

Slide 55

Slide 55 text

ίʔυϑΝʔετͰεΩʔϚΛग़ྗ͢Δ w εΩʔϚΛμϯϓ͢Δ w εΩʔϚ͸ϦϙδτϦʹೖΕΔ w εΩʔϚͷมߋ͸ϨϏϡʔ͢Δ w ࠷৽ͷεΩʔϚ͕ग़ྗ͞Ε͍ͯΔ͔͸ςετͰ୲อ w IUUQTHSBQIRMSVCZPSHUFTUJOHTDIFNB@TUSVDUVSFIUNM # lib/tasks/graphql.rake task dump_schema: :environment do schema_defn = GraphqlRubyExerciseSchema.to_definition schema_path = "app/graphql/schema.graphql" File.write(Rails.root.join(schema_path), schema_defn) puts "Updated #{ schema_path}" end

Slide 56

Slide 56 text

(SBQI2-"1*Λ࣮૷͢Δ

Slide 57

Slide 57 text

(SBQI2-"1*ͷ࣮૷ w HSBQIRMSVCZΛ࢖͏ w ϥΠϒϥϦͷυΩϡϝϯτʹै͏

Slide 58

Slide 58 text

ͻͱ·ͣΦϒδΣΫτܕΛ࡞Δ w ΦϒδΣΫτͱϑΟʔϧυ͕ॏཁ w %#্ͷߏ଄ʹ߹ΘͤΔඞཁ͸ͳ͍ w HSBQIRMSVCZͰ͸ $ rails g graphql:object Model w "DUJWF3FDPSEͷϞσϧͷ৘ใ͕ࣗಈతʹ࢖ΘΕΔ w ϛεϦʔσΟϯάͰ͸͋Δ module Types class UserType < Types :: BaseObject field :name, String, null: false end end

Slide 59

Slide 59 text

جຊతʹ͸ϦκϧόΛॻ͚͹͍͍ Ϧκϧό˺ίϯτϩʔϥ w ϑΟʔϧυΛղܾ͢Δͷ͕Ϧκϧό w (SBQI2-ʹಛ༗ͷॲཧΛॻ͘ w HSBQIRMSVCZͰ͸ w ϑΟʔϧυͱಉ໊ͷϝιου module Types class QueryType < Types :: BaseObject include GraphQL :: Types :: Relay : : HasNodeField include GraphQL :: Types :: Relay : : HasNodesField field :all_blogs, BlogType.connection_type def all_blogs Blog.all.order(id: :desc) end end end

Slide 60

Slide 60 text

Ϧκϧό͸ωετ͢Δ w ϦκϧόͰಘΒΕͨΦϒδΣΫτ͕ 
 ·ͨϦκϧόΛ࣋ͭ w 2VFSZˠ#MPHˠ1PTU w ศར w /໰୊ͷԹচʜʜ module Types class BlogType < Types :: BaseObject implements GraphQL :: Types : : Relay :: Node global_id_field :id field :owner, UserType, null: false def owner object.owner end field :name, String, null: false field :posts, PostType.connection_type do end def posts object.posts.order(datetime: :desc) end end end

Slide 61

Slide 61 text

ϦκϧόΛॻ͘ͱ͖ͷࢦ਑ w ΫΤϦͷϦκϧό͸ݺͼग़͞ΕΔॱং͕ෆఆͰ͋ΔલఏΛஔ͘ w ϥΠϒϥϦʹΑͬͯ͸ฒྻʹ࣮ߦ͞ΕΔՄೳੑ͕͋Δ w ෭࡞༻͕ͳ͍Α͏ʹ w ϛϡʔςʔγϣϯ͸ॻ͍ͨॱʹ࣮ߦ͞ΕΔͷͰؾʹ͠ͳ͍ w ϦκϧόʹϏδωεϩδοΫΛॻ͔ͳ͍ w ϏδωεϩδοΫ͸Ϟσϧʹॻ͘

Slide 62

Slide 62 text

ΠϯλʔϑΣʔε΍ϢχΦϯΛฦ͢ͱ͖͸஫ҙ ΦϒδΣΫτͱܕͷରԠΛࣔ͢ඞཁ͕͋Δ w ΠϯλʔϑΣʔεͱͯ͠ฦ͢ͱ͖ 
 ࣮ࡍʹ͸Ͳͷܕ͔ϥΠϒϥϦʹ఻͑Δ w HSBQIRMSVCZͰ͸ w Schema.resolve_type def self.resolve_type(abstract_type, obj, ctx) case obj when User Types :: UserType when Blog Types :: BlogType when Post Types :: PostType else raise(GraphQL :: RequiredImplementationMissingError) end end

Slide 63

Slide 63 text

3FMBZʹରԠͤ͞Δ HSBQIRMSVCZ͕͍͍ͩͨ΍ͬͯ͘ΕΔ $ rails generate \ graphql:install - - relay w (MPCBM*%Λར༻ͨ͠/PEFͷ࣮૷ def self.id_from_object(object, type_definition, query_ctx) object_id = object.to_global_id.to_s object_id = object_id.sub("gid: //#{ GlobalID.app}/", "") encoded_id = Base64.urlsafe_encode64(object_id) encoded_id = encoded_id.sub( /= +/, "") type_hint = type_definition.graphql_name.first " #{ type_hint}_ # { encoded_id}" end def self.object_from_id(encoded_id_with_hint, query_ctx) _type_hint, encoded_id = encoded_id_with_hint.split("_", 2) id = Base64.urlsafe_decode64(encoded_id) full_global_id = "gid: //#{ GlobalID.app}/ #{ id}" GlobalID :: Locator.locate(full_global_id) end

Slide 64

Slide 64 text

3FMBZʹରԠͤ͞Δ /PEFΠϯλʔϑΣʔε • GraphQL :: Types :: Relay : : Node w HMPCBM@JE@ fi FMEΛࢦఆ module Types class UserType < Types :: BaseObject implements GraphQL :: Types :: Relay :: Node global_id_field :id field :name, String, null: false end end

Slide 65

Slide 65 text

3FMBZʹରԠͤ͞Δ $POOFDUJPO w connection_type w ಺෦తʹP ff TFUϕʔεʹͳ͍ͬͯΔ module Types class QueryType < Types :: BaseObject field :all_blogs, BlogType.connection_type def all_blogs Blog.all.order(id: :desc) end end end

Slide 66

Slide 66 text

ίϯςΩετΛ࢖͏ ϦΫΤετʹඥ͍ͮͨσʔλ͸ίϯςΩετʹ֨ೲ͢Δ w ϩάΠϯϢʔβʔͳͲ w ΫΤϦΛ࣮ߦ͢ΔίϯτϩʔϥʔͰ 
 ίϯςΩετΛ࡞Δ def execute variables = prepare_variables(params[:variables]) query = params[:query] operation_name = params[:operationName] context = { # Query context goes here, for example: # current_user: current_user, } result = GraphqlRubyExerciseSchema.execute( query, variables: variables, context: context, operation_name: operation_name ) render json: result rescue StandardError = > e raise e unless Rails.env.development? handle_error_in_development(e) end

Slide 67

Slide 67 text

(SBQIJ2-Λ࢖͏ (SBQI2-*%& $ rails generate graphql:install w HSBQIRMSVCZͰ͸ w /graphiqlʹࣗಈͰηοτΞοϓ͞ΕΔ w 3BJMT͕"1*Ϟʔυͷ৔߹͸ηοτΞοϓ͞Εͳ͍ w ผʹ༻ҙ͢Δͱศར

Slide 68

Slide 68 text

(SBQI2-"1*࣮૷্ͷཹҙ఺

Slide 69

Slide 69 text

/໰୊ w BVUIPSͷϦκϧόΛφΠʔϒʹ࣮૷ w 1PTUͷ਺͚ͩ4&-&$5 SELECT * FROM author WHERE id = ?; type Author { id: ID! name: String! } type Post { id: ID! title: String! author: Author! } type Query { allPosts(first: Int!, after: String): PostConnection! }

Slide 70

Slide 70 text

/໰୊ରࡦ σʔλϩʔμʔΛ࢖͏ w ಡΈࠐΈΛ஗Ԇͤ͞Δ࢓૊Έ SELECT * FROM author WHERE id IN (?, ?, ?); w HSBQIRMSVCZͰ͸ w GraphQL :: DataloaderΛ࢖͏ class Sources : : ActiveRecordObject < GraphQL : : Dataloader :: Source def initialize(model_class) @model_class = model_class end def fetch(ids) records = @model_class.where(id: ids) ids.map { |id| records.find { |r| r.id = = id.to_i } } end end field :author, UserType, null: false def author dataloader .with(Sources :: ActiveRecordObject, :: User) .load(object.author_id) end

Slide 71

Slide 71 text

%P4߈ܸ w ෳࡶͳΫΤϦͰ%P4߈ܸͰ͖Δ w ಛʹ࠶ؼతͳεΩʔϚͰ͸༰қ w #MPHˠ1PTUˠ#MPHˠ1PTUˠʜ query { blog(id: "1") { posts(first: 100) { edges { node { blog { posts(first: 100) { edges { node { . . . } } } } } } } } }

Slide 72

Slide 72 text

%P4߈ܸରࡦ ΫΤϦ౰ͨΓͷॲཧྔΛ੍໿͢Δ w λΠϜΞ΢τͤ͞Δʢuse GraphQL : : Schema : : Timeout, max_seconds: 2ʣ w ΫΤϦͷ"45ͷ࣌఺Ͱ੍໿ w ਂ੍͞ݶʢmax_depth 10ʣ w ෳࡶ͞Ͱ੍ݶʢmax_complexity 100ʣ w Ϩʔτ੍ݶ w (JU)VC͸࣌ؒ౰ͨΓͷෳࡶ͞ͷείΞͰ੍ݶ͍ͯ͠Δ

Slide 73

Slide 73 text

ඇެ։"1*ͳΒ ΫϥΠΞϯτͷ։ൃऀ͕ΠϯαΠμʔʹݶΒΕΔͳΒ w ϓϩμΫγϣϯͰ͸*OTUSPTQFDUJPOΛ௵͢ w 1FSTJTUFE2VFSZΛ࢖͏

Slide 74

Slide 74 text

ϓϩμΫγϣϯͰ͸*OUSPTQFDUJPOΛ௵͢ εΩʔϚ৘ใΛ஌ΒΕʹ͘͘͢Δ w *OUSPTQFDUJPO͸(SBQI2-ͷεΩʔϚ৘ใΛऔಘ͢ΔಛผͳΫΤϦ w ࢓༷ͰఆΊΒΕ͍ͯΔ w ֎෦͔ΒεΩʔϚ৘ใ͕ಘΒΕΔʢ(SBQIJ2-ͳͲͰ׆༻͞ΕΔʣ w ϓϩμΫγϣϯ؀ڥͰ͸*OUSPTQFDUJPOͰ͖ͳ͓ͯ͘͘͠ • disable_introspection_entry_points if Rails.env.production? w εΩʔϚ৘ใ͕ਪଌͰ͖ͳ͘ͳΔΘ͚Ͱ͸ͳ͍͜ͱʹ஫ҙ

Slide 75

Slide 75 text

1FSTJTUFE2VFSZΛ࢖͏ ҙਤ͠ͳ͍ΫΤϦΛड͚෇͚ͳ͍ w ΫϥΠΞϯτ͕ૹ৴͢ΔΫΤϦΛϋογϡ஋ͱ૊Ͱαʔόʔʹొ࿥͓ͯ͘͠ w ΫϥΠΞϯτ͔Β͸࣮ࡍͷΫΤϦͷ୅ΘΓʹϋογϡ஋ΛૹΔ w ΫΤϦͷ಺༰Λ஌ΒΕͣʹࡁΉ w ࣄલʹొ࿥͞Ε͍ͯͳ͍ΫΤϦΛ๷͛Δ • GraphQL :: Pro : : OperationStore w ΫϥΠΞϯτϥΠϒϥϦͷ΄ͱΜͲ͕ରԠ͍ͯ͠Δ

Slide 76

Slide 76 text

ΦϒβʔόϏϦςΟͷ௿Լ w (SBQI2-͸୯ҰͷΤϯυϙΠϯτΛ࢖͏ w POST /graphql w 3&45͸Ϧιʔε΍ॲཧ͝ͱʹΤϯυϙΠϯτ͕෼͔Ε͍ͯͨ w (SBQI2-ͷ৔߹͸ΞΫηεϩάͰ͸৘ใ͕଍Γͳ͍ w ฏۉͷϨΠςϯγ΍Τϥʔ཰Λݟͯ΋Կ͕ى͖͍ͯΔ͔Θ͔Βͳ͍

Slide 77

Slide 77 text

ΦϒβʔόϏϦςΟΛ֬อ͢Δ w τϨʔγϯά͢Δ w Ϧκϧόͷݺͼग़͠΍*0Λه࿥ • GraphQL :: Tracing

Slide 78

Slide 78 text

஗͗͢Δ(SBQI2-"1*ࣄ݅ w 1ZUIPOͰ(SBQI2-"1*Λ࡞͍͕ͬͯͨ૝ఆΑΓ஗͍෦෼͕͋ͬͨ w ϓϩϑΝΠϦϯά͍ͯ͘͠ͱɺ$16͕ϘτϧωοΫ w +40/ʹγϦΞϥΠζ͢Δͱ͜Ζ͕஗͔ͬͨ w ཁૉ͕ଟ͔ͬͨΓωετ͕ਂ͔ͬͨΓ͢ΔͱϑΟʔϧυ਺͕ଟ͘ͳΔ w +*5ίϯύΠϧͰ͖ͨΒ଎͘ͳΓͦ͏ʁ

Slide 79

Slide 79 text

·ͱΊ

Slide 80

Slide 80 text

(SBQI2- w ཁٻ͞ΕΔ஌ࣝͷྔ͕ଟΊ w ϦονͳΫϥΠΞϯτ޲͚ͷ8FC"1*ʹ͸ͦΕ͚ͩͷ͜ͱ͕ඞཁ w 8FC"1*ʹඞཁͳϓϥΫςΟε͕͢΂ͯ٧·͍ͬͯΔ w ͭ·Γʜ w (SBQI2-͸Ϩʔϧ w HSBQIRMSVCZ͸Α͘Ͱ͖͍ͯΔ