Slide 1

Slide 1 text

1 ϓϩτίϧɺΠϯλʔϑΣʔεͱͯ͠ͷ (SBQI2- &ODSBGUαʔόʔͱΫϥΠΞϯτΛ݁Ϳٕज़ !TPOBUBSEͦͳଠ

Slide 2

Slide 2 text

Stack CTO ͦͳଠ @sonatard

Slide 3

Slide 3 text

3 ఏڙαʔϏε w "QQJGZ w 4IPQJGZͷΞϓϦΛ/P$PEFͰϦϦʔε w J04ɺ"OESPJE w 8FC্ͰΞϓϦͷσβΠϯΛมߋՄೳ w 7*1 w 4IPQJGZʹॊೈͳձһϓϩάϥϜΛఏڙ w ϙΠϯτɺձһϥϯΫɺϦϫʔυɺ༑ୡ঺հ w ৽αʔϏε w ։ൃத

Slide 4

Slide 4 text

4 ٕज़ελοΫ w J04 w 4XJGU6* w "QPMMPJ04 w "OESPJE w +FUQBDL$PNQPTF w "QPMMP,PUMJO w 8FC w 5ZQF4DSJQU w "QPMMP w #BDLFOE w (P w HRMHFO w ($1$MPVE3VOͳͲ

Slide 5

Slide 5 text

5 4UBDLࣾͷ"1*ͷྺ࢙ w ೥ w 1SPUPDPM#V ff FSTPO)551 w ೥Ҏ߱ w (SBQI2-

Slide 6

Slide 6 text

(SBQI2-ͱ͸

Slide 7

Slide 7 text

7 (SBQI2-ͱ͸ w جຊ w 0WFSGFUDIͷղফ w ඞཁͳ஋͚ͩΛऔಘ w 6OEFSGFUDIͷղফ w ౓ͷϦΫΤετͰඞཁͳ஋Λ͢΂ͯऔಘ w εΩʔϚۦಈ։ൃ w εΩʔϚ͔ΒόοΫΤϯυͱΫϥΠΞϯτͷίʔυΛੜ੒ w ୯ҰΤϯυϙΠϯτʹ2VFSZΛૹ৴͢Δ w IUUQTFYNBQMFDPNHSBQIRM

Slide 8

Slide 8 text

8 2VFSZ஋ͷऔಘ type Query { viewer: User! } type User implements Node { id: ID! order: Order! } type Order implements Node { id: ID! # default஋ΛઃఆͰ͖Δ product(hasStock: Boolean = true): Product! } type Product implements Node { id: ID! name: String! } query GetProduct { viewer { order { product { name } } } } 4DIFNB 2VFSZ

Slide 9

Slide 9 text

9 .VUBUJPO࡞੒ɺߋ৽ɺ࡟আͳͲ type Mutation { productCreate(input: ProductInput!): ProductCreatePayload! } input ProductInput { name: String! price: String! } type ProductCreatePayload { product: Product } mutation ProductCreate($input: ProductInput!){ productCreate(input: $input) { product { id Name } } } 4DIFNB 2VFSZ

Slide 10

Slide 10 text

10 4VCTDSJQUJPOετϦʔϛϯάͰ஋Λऔಘ type Subscription { viewer: User! } type User implements Node { id: ID! order: Order! } type Order implements Node { id: ID! product: Product! } type Product implements Node { id: ID! name: String! } subscription GetProduct { viewer { order { product { name } } } } 4DIFNB 2VFSZ

Slide 11

Slide 11 text

11 εΩʔϚۦಈ։ൃ w (SBQI2-4DIFNBΛݩʹؔ࿈͢Δίʔυ͕ੜ੒͢ΔͷͰɺܕͷෆҰக͕ى͖ͳ͍ type Query { node(id: ID!): Node! viewer: User! adminViewer: Admin! }

Slide 12

Slide 12 text

12 (SBQI2-ͷϝϦοτ w σβΠϯͷϢʔεέʔεʹҾͬுΒΕͯɺ"1*Λมߋ͢Δඞཁ͕ͳ͍ w ΫϥΠΞϯτʮը໘9ʹ:Λදࣔ͢Δඞཁ͕Ͱ͖ͨͷͰɺ9"1*Ͱ:ΛҾ͖͍ͨʯ w 3&45ύλʔϯΫϥΠΞϯτଆ͕ଥڠ͢Δ৔߹ w όοΫΤϯυʮ9"1*ͷ੹຿͔Β:͸֎ΕΔͷͰ:"1*Λ࣮ߦͯ͠ཉ͍͠ʯ w ΫϥΠΞϯτʮ9"1*ͱ:"1*ճ࣮ߦ͢Δ͔ʜ355Ͱ69མͪ͠ίʔυ΋ෳࡶʹͳΔͳʯ w 3&45ύλʔϯόοΫΤϯυଆ͕ଥڠ͢Δ৔߹ w όοΫΤϯυʮ9"1*Ͱ:ฦ͢Α͏ʹ͢Δ͔ʜ੹຿ͱͯ͠ҧ࿨ײ͋Δ͠ɺଞͷը໘Ͱ࢖Θͳ͍ͷ ʹ༨ܭͳ3FBE૿͑Δͳɻ΋͘͠͸ઐ༻ͷ9:"1*௥Ճ͢Δ͔ʜʯ w (SBQI2-ͷ৔߹ΫϥΠΞϯτόοΫΤϯυͲͪΒ΋޾ͤ w όοΫΤϯυʮը໘9༻ʹ9ͱ:ΛҾ͘2VFSZΛॻ͍ͯऔಘ͍͍ͯ͠Αଞͷը໘Ͱ͸9͚ͩΛҾ͘ 2VFSZॻ͚͹ຖճ:ΛҾ͘ඞཁͳ͍͔ΒύϑΥʔϚϯεͷ໰୊΋ͳ͍Αʯ w ΫϥΠΞϯτʮ355ͰࡁΉ͠ɺίʔυ͸γϯϓϧɺը໘Ͱඞཁͳ஋͢΂ͯऔಘͰ͖ͯخ͍͠ʯ w όοΫΤϯυΤϯδχΞͱͯ͠ͷ (SBQI2-࠷େͷϝϦοτ

Slide 13

Slide 13 text

6OJPOɺ*OUFSGBDF

Slide 14

Slide 14 text

14 6OJPO union Announcement = TextAnnouncement | URLAnnouncement | ProductAnnouncement type TextAnnouncement { id: ID! text: String! } type URLAnnouncement { id: ID! url: String! } type ProductAnnouncement { id: ID! product: Product! } query Announcements { announcements { __typename ... on TextAnnouncement { id text } ... on URLAnnouncement { id url } ... on ProductAnnouncement { id product { id name price } } } } 4DIFNB 2VFSZ type Product { id: ID! name: String! price: Int! }

Slide 15

Slide 15 text

15 const Announcements: React.FC = () => { const { data } = useQuery(AnnouncementsDocument); return (

Announcements

    {announcements.map((announcement) => { switch (announcement.__typename) { case "TextAnnouncement": return
  • Text: {announcement.text}
  • ; case "URLAnnouncement": return (
  • URL: {announcement.url}
  • ); case "ProductAnnouncement": return
  • Product: {announcement.product.name} - $ {announcement.product.price}
  • ; default: return null; } })}
); }; (SBQI2-Ͱ͸VOJPOͷߏ଄Λద੾ͳܕʹ ஋͕ೖͬͨঢ়ଶͰऔಘͰ͖Δ

Slide 16

Slide 16 text

16 *OUFSGBDF interface Announcement { id: ID! title: String! } type TextAnnouncement implements Announcement { id: ID! title: String! text: String! } type URLAnnouncement implements Announcement { id: ID! title: String! url: String! } type ProductAnnouncement implements Announcement { id: ID! title: String! product: Product! } query Announcements { announcements { __typename id title ... on TextAnnouncement { text } ... on URLAnnouncement { url } ... on ProductAnnouncement { product { id name price } } } } 4DIFNB 2VFSZ JEͱUJUMF͸JOUFSGBDFʹఆٛ͞Ε͍ͯΔͨΊ ܕʹΑΔ෼ذ͸ෆཁͰɺ ௚઀ར༻͢Δ͜ͱ͕Ͱ͖Δ

Slide 17

Slide 17 text

17 const Announcements: React.FC = () => { const { data } = useQuery(AnnouncementsDocument); return (

Announcements

    {announcements.map((announcement) => { const content = (() => { switch (announcement.__typename) { case "TextAnnouncement": return

    Text: {announcement.text}

    ; case "URLAnnouncement": return (

    URL: {announcement.url}

    ); case "ProductAnnouncement": return

    Product: {announcement.product.name} - ${announcement.product.price}

    ; default: return null; } })(); return (
  • {announcement.title}

    {content}
  • JEͱUJUMF͸JOUFSGBDFʹఆٛ͞Ε͍ͯΔͨΊ ܕʹΑΔ෼ذ͸ෆཁͰɺ ௚઀ར༻͢Δ͜ͱ͕Ͱ͖Δ

Slide 18

Slide 18 text

2VFSZͷ֦ு

Slide 19

Slide 19 text

19 2VFSZ!EFGFSEJSFDUJWF query { person(id: "cGVvcGxlOjE=") { ...HomeWorldFragment @defer(label: "homeWorldDefer") name } } fragment HomeWorldFragment on Person { homeworld { name } } w !EFGFSEJSFDUJWF͸෇༩ͨ͠2VFSZͷ༏ઌ౓ΛԼ͛Δ w (SBQI2-͸ɺෳ਺ͷ஋Λಉ࣌ʹऔಘͰ͖Δ͕ɺ͢΂ͯͷ݁Ռ͕ἧΘͳ͍ͱϨεϙϯεΛ ฦ͞ͳ͍ɻ!EFGFSEJSFDUJWFΛઃఆ͢Δ͜ͱͰɺ४උ͕Ͱ͖ͨ'JFMEΛઌʹฦ͢͜ͱͰԠ ౴ੑ͕޲্͢Δɻ

Slide 20

Slide 20 text

20 2VFSZ!TUSFBNEJSFDUJWF query { person(id: "cGVvcGxlOjE=") { name films @stream(initialCount: 2, label: "filmsStream") { title } } } w !TUSFBNEJSFDUJWF͸෇༩ͨ͠2VFSZͷ݁ՌΛετϦʔϜͰड͚औΔ w -JTUͷϨεϙϯεΛऔಘ͢Δࡍʹେ͖ͳ-JTUͷ৔߹ʹ!TUSFBNEJSFDUJWFΛࢦఆ͢Δͱ JJUJBM$PVOUͰઃఆͨ͠਺ͷϨεϙϯεΛઌʹड͚औΔ͜ͱͰԠ౴ੑΛ্͛Δɻ

Slide 21

Slide 21 text

3FMBZ(SBQI2-4FSWFS4QFDJ fi DBUJPO

Slide 22

Slide 22 text

22 (SBQI2-4FSWFS4QFDJ fi DBUJPO/PEFJOUFSGBDF type Query { node(id: ID!): Node! } interface Node { id: ID! @goField(forceResolver: true) } query GetProduct($productID: ID!) { node(id: $productID) { ... on Product { id name } } } w *%Λ࣋ͭΦϒδΣΫτ͸/PEFJOUFSGBDFΛ࣮૷͢Δɻ w ͜ΕΛ࣮૷͢ΔͨΊʹ͸ɺ*%͔ΒͲͷΦϒδΣΫτ͔Λ൑ผͰ͖Δඞཁ͕͋Γ·͢ɻ w (MPCBM0CKFDU*EFOUJ fi DBUJPO w 4IPQJGZͳͲ͸ҎԼͷΑ͏ͳ*%ܗࣜΛ࠾༻͍ͯ͠·͢ɻHJETIPQJGZ1SPEVDU

Slide 23

Slide 23 text

23 (SBQI2-$VSTPS$POOFDUJPOT4QFDJ fi DBUJPO w $POOFDUJPO w -JTUܗࣜͷ஋ΛϖʔδωʔγϣϯͰऔಘ͢Δඞཁ͕͋Δ৔߹ͷ4DIFNBఆٛͷఏҊ w 999$POOFDUJPOUZQFΛఆٛ w FEHFTPSOPEFTϑΟʔϧυΛ࣋ͭ w QBHF*OGPΛ࣋ͭ w FEHFTͷ৔߹͸ɺ999&EHFΛఆٛ w /PEFϑΟʔϧυΛ࣋ͭ w 1BHF*OGPUZQFΛఆٛ w Χʔιϧͷ։࢝ͱऴྃ஍఺ͷ৘ใ w લޙͷϖʔδωʔγϣϯͷଘࡏͷ༗ແ type UserConnection { pageInfo: PageInfo! edges: [UserEdge!]! nodes: [User!] } type UserEdge { node: User! } type PageInfo { startCursor: String! endCursor: String! hasNextPage: Boolean! hasPreviousPage: Boolean! }

Slide 24

Slide 24 text

ϑΥʔϚοτ

Slide 25

Slide 25 text

25 2VFSZɺ.VUBUJPOͷϑΥʔϚοτ w 3FRVFTU w 1045ͷ#PEZ { "query": "...", "operationName": "...", "variables": { "myVariable": "someValue", ... } } { "data": { ... }, "errors": [ ... ] } w 3FTQPOTF w #PEZ

Slide 26

Slide 26 text

26 2VFSZɺ.VUBUJPOͷϑΥʔϚοτ w 3FRVFTU w (&5ͷRVFSZQBSBNFUFS http://myapi/graphql?query={me{name}} w 1FSTJTUFE2VFSJFT w 2VFSZΛ4)"ͰϋογϡԽͨ͠΋ͷΛૹ৴ w ϦΫΤεταΠζΛখ͘͞Ͱ͖Δ w (&5ͱར༻͢Δ͜ͱͰ$%/ͰΩϟογϡՄೳʹͳΔ w ొ࿥͞Ε͍ͯΔϋογϡͷΈΛ࣮ߦՄೳʹ͢Δ͜ͱ΋Ͱ͖Δ

Slide 27

Slide 27 text

27 4FSJBMJ[BUJPO'PSNBU w (SBQI2-ͷ4FSJBMJ[BUJPO'PSNBU͸+40/ʹݶఆ͞Ε͍ͯͳ͍ w ݱ࣮తͳੈͷதͷ࣮૷ͱͯ͠͸େ൒͕+40/ w .645 w .BQɺ-JTUɺ4USJOHɺ/VMM w 4)06-% w #PPMFBOɺ*OUɺ'MPBUɺ&OVN w ରԠ͍ͯ͠ͳ͍৔߹͸4USJOHͱͯ͠ૹΒΕΔ (SBQI2-7BMVF +40/7BMVF .BQ 0CKFDU -JTU "SSBZ /VMM OVMM 4USJOH 4USJOH #PPMFBO USVFPSGBMTF *OU /VNCFS 'MPBU /VNCFS &OVN7BMVF 4USJOH

Slide 28

Slide 28 text

4DIFNB؅ཧ

Slide 29

Slide 29 text

29 4DIFNBͷ؅ཧ w (SBQI2-2VFSZͷิ׬΍ίʔυੜ੒ʹ4DIFNB͕ඞཁ w 4DIFNBͷ৘ใΛ֤छπʔϧ͕௚઀ΤϯυϙΠϯτ͔Β*OUSPTQFDUJPO2VFSZʹΑΓ औಘ w 4DIFNBϑΝΠϧΛΤϯυϙΠϯτ͔Β*OUSPTQFDUJPO2VFSZʹΑΓμ΢ϯϩʔυ͠ ͯɺμ΢ϯϩʔυͨ͠ϑΝΠϧΛ֤छπʔϧ͕ಡΈࠐΉ w 4DIFNBϑΝΠϧΛϦϙδτϦ͔Βμ΢ϯϩʔυͯ͠ɺμ΢ϯϩʔυͨ͠ϑΝΠϧ Λ֤छπʔϧ͕ಡΈࠐΉ w *OUSPTQFDUJPO2VFSZΛར༻ͨ͠εΩʔϚμ΢ϯϩʔυπʔϧ w IUUQTHJUIVCDPNHRMHPHFUHSBQIRMTDIFNB

Slide 30

Slide 30 text

"SDIJUFDUVSF

Slide 31

Slide 31 text

31 GBDUPSBQQ w &WFOU4PVSDJOHɺ$234ɺ6OJEJSFDUJPOBM%BUB fl PXʹӨڹΛड͚͍ͯΔ w .VUBUJPO͸ΠϕϯτΛه࿥ͯ͠ଈ࠲ʹϨεϙϯεΛฦͨ͢ΊԠ౴ੑ͕ߴ͍ w .VUBUJPOͷ݁ՌΛ଴ͪड͚ͯɺར༻͢ΔͷͰ͸ͳ͘.VUBUJPOʹΑΔมߋ͸4VCTDSJQUJPO Λհͯ͠औಘ͢Δ୯ํ޲σʔλϑϩʔ w .VUBUJPOΠϕϯτͷอଘ৽͍͠ঢ়ଶͷ࡞੒4VCTDSJQUJPOͰ௨஌

Slide 32

Slide 32 text

32 'FEFSBUJPO "QPMMP'FEFSBUJPO ɺ4DIFNB4UJUDIJOH w ෳ਺ͷ(SBQI2-"1*Λ૊Έ߹ΘͤͨεʔύʔάϥϑΛ࡞੒͢ΔͨΊͷΞʔΩςΫνϟ w େ͖ͳձࣾͰ͸ɺ(SBQI2-͸(BUFXBZͱͯ͠ѻΘΕͯɺഎޙͷ.JDSPTFSWJDFT΁ͷϦΫ ΤετΛ؅ཧ͢Δɻ w .JDSPTFSWJDFT͸νʔϜ୯ҐͰ෼ׂ͞Ε͍ͯΔ͕ɺ(SBQI2-ͷ(BUFXBZ͸ͭͳͷͰଟ͘ ͷνʔϜ͕มߋ͢ΔͨΊσϓϩΠͷͰಠཱੑͳͲ͕೉͘͠ͳΔɻ w ͦ͜Ͱ'FEFSBUJPOΛ࢖͏͜ͱͰɺ(SBQI2-Λ෼ׂ͢Δɻ

Slide 33

Slide 33 text

33 'FEFSBUJPO "QPMMP'FEFSBUJPO .JDSPTFSWJDFT (BUFXBZ (BUFXBZͷ෼ׂ

Slide 34

Slide 34 text

1SPUPDPM#V ff FSTPO)551ͱͷൺֱ

Slide 35

Slide 35 text

35 1SPUPDPM#V ff FSTPO)551ͱͷൺֱ w εΩʔϚͷදݱ w (SBQIߏ଄ΛදݱͰ͖Δ w 6OJPOɺ*OUFSGBDF͕ඪ४Ͱ࣋ͭͨΊදݱ͠΍͍͢ w SFTPMWFSʹΑΓϑΟʔϧυͷ௥Ճ͕͠΍͍͢ w طଘͷ2VFSZ͸औಘ͍ͯ͠ͳ͍ͷͰӨڹ͠ͳ͍ w ϑΟʔϧυͷ࡟আͷ͠΍͢͞͸มΘΒͳ͍ w εΩʔϚ؅ཧ w *OUSPTQFDUJPO2VFSZʹΑΓΤϯυϙΠϯτ͔Βμ΢ϯϩʔυPS௚઀ͷࢀর͕Ͱ͖Δ w ੩తղੳπʔϧͷ࣮૷ͷ͠΍͢͞ w ࣮૷͍ͨ͠ݴޠͷ"451BSTFS͕͋Ε͹ࠩ͸ͳ͍

Slide 36

Slide 36 text

36 1SPUPDPM#V ff FSTPO)551ͱͷൺֱ w ಠ࣮ࣗ૷ͷ௥Ճ w (SBQI2-EJSFDUJWF w 1SPUPDPM#V ff FST1MVHJO w (SBQI2-ͷEJSFDUJWFͷํ͕ؾܰʹ௥ՃͰ͖Δ w .JDSPTFSWJDFT w .JDSPTFSWJDFTؒΛ(SBQI2-Ͱ࣮૷͢ΔͱεΩʔϚઃܭʹۤ࿑͢Δ w .JDSPTFSWJDFT͸H31$ͷࢿ࢈͕ଟ͍ w (SBQI2-͸(BUFXBZʹݶఆͨ͠ํ͕ߟ͑ํ͸γϯϓϧ w 'FEFSBUJPO͸(BUFXBZͷ෼ׂʹ׆༻͢Δ

Slide 37

Slide 37 text

37 1SPUPDPM#V ff FSTPO)551ͱͷൺֱ w ϓϩτίϧ΁ͷґଘ w (SBQI2-͸ྑ͘΋ѱ͘΋ଟ͘ͷϓϥΫςΟε͕࢓༷΍ϑϨʔϜϫʔΫʹଘࡏ͢ΔͨΊґ ଘ͕ڧ͍ w 1SPUPDPM#V ff FSTPO)551͸γϯϓϧͰ͋Γɺଞͷྨࣅϓϩίτϧ΁ͷҠߦ΋༰қ w Ϋϥ΢υαʔϏεͷରԠ w 8FCαʔϏε͕3&45΍+40/Λத৺ʹൃల͖ͯͨ͠ͷͰɺ(SBQI2-ͱϚον͠ͳ͍͜ͱ ͕ଟʑ͋Δ w ྫ ϦΫΤετͷղੳΛΤϯυϙΠϯτ͝ͱʹ΍͍ͬͯΔͱɺ͢΂ͯͷϦΫΤετΛ HSBQIRMΤϯυϙΠϯτʹ౤͛Δ(SBQI2-Ͱ͸෼ੳ͕೉͍͠ w (SBQI2-ઐ༻αʔϏεͷར༻΍ɺطଘαʔϏεͷ্Ͱ(SBQI2-Λద༻ͤ͞ΔͨΊͷ޻෉ ͕ඞཁʹͳΔ w ΞϓϦ w "QPMMPJ04ɺ"QPMMP,PUMJO͕ൃల్্ w (SBQI2-͸1SPUPDPM#V ff FSTΑΓϥΠϒϥϦͷӨڹ͕େ͖͍

Slide 38

Slide 38 text

38 1SPUPDPM#V ff FSTPO)551ͱͷൺֱ w Ҏ্ͷ͜ͱ͔Βɺ(SBQI2-Λར༻͢Δࡍʹ͸ɺ(SBQI2-ʹϕοτͯ͠ɺ৔߹ʹΑͬͯ͸ ࣗ෼ͨͪͰղܾ͢Δ࢟੎͕ඞཁʹͳΔ

Slide 39

Slide 39 text

·ͱΊ

Slide 40

Slide 40 text

40 ެࣜɾඇެࣜͷ੔ཧ w (SBQI2-4QFD w 2VFSZɺ.VUBUJPOɺ4VCTDSJQUJPO w (SBQI2-4QFD8PSLJOH%SBGU w !EFGFSɺ!TUSFBN w 3FMBZ w /PEF w $POOFDUJPO w "QPMMP w 'FEFSBUJPO w 5IF(6*-% w 4DIFNB4UJUIJOH w )BTVSB w GBDUPS"QQ w