Slide 1

Slide 1 text

DIY GraphQL Code Generation GraphQL Tokyo 2020.08.28

Slide 2

Slide 2 text

Client Side Code Generation - ͳͥGraphQLͰCodeGen͕ඞཁͳͷ͔ - ClientͷϦΫΤετ(query)ͷܗʹԠͯ͡Response͕ܾఆ͞ΕΔͷ͕ GraphQLͷಛ௃ - ಛʹ੩తܕ෇ݴޠͷ৔߹ʮͲͷΑ͏ͳσʔλ͕ฦͬͯ͘Δ͔ʯ͕ඞཁ ʹͳΔ

Slide 3

Slide 3 text

Client Side Code Generation export default () => { const { data } = useQuery< GitHubQuery, GitHubQueryVariables >(query, { variables: { first: 100 } }); if (!data) return null; return (
    {data.viewer?.repositories?.nodes?.map(repo => (
  • {repo?.description}
  • ))}
); }; const repositoryFragment = gql` fragment RepositoryFragment on Repository { description } `; const query = gql` ${repositoryFragment} query GitHubQuery($first: Int!) { viewer { repositories(first: $first) { nodes { id ...RepositoryFragment } } } } `;

Slide 4

Slide 4 text

Client Side Code Generation - ͜͏͍͏ܕ৘ใ͕͋Ε͹ɺલϖʔδͷ data ΛܕνΣοΫͰ͖Δ export type RepositoryFragment = { description: string | null; }; export type GitHubQuery = { viewer: { repositories: { nodes: (({ id: string; } & RepositoryFragment) | null)[] | null; }; }; }; export type GitHubQueryVariables = { first: number; };

Slide 5

Slide 5 text

Client Side Code Generation - queryʹଘࡏ͠ͳ͍ϑΟʔϧυʹରͯ͠ɺίʔυ͔ΒͷΞΫηεΛېࢭͰ ͖ΔͨΊɺCodeGen͸ʮUnder FetchingΛ๷ࢭ͢Δ࢓૊Έʯͱߟ͑Δ͜ ͱ΋Ͱ͖Δ - ※ Under Fetching: ຊདྷClientʹඞཁͳϑΟʔϧυΛqueryʹॻ͖๨Εͯ͠·͏͜ͱɻ ػೳཁ্݅ͷෆඋʹͳΔɻ ରͱͳΔͷ͸ Over FetchingɻෆཁͳϑΟʔϧυ͕queryʹࡌ͍ͬͯΔঢ়ଶɻੑೳྼ ԽΛҾ͖ى͜͢ɻඇػೳཁ݅ͷෆඋͱͳΔɻ

Slide 6

Slide 6 text

CodeGen tools - ੈͷதʹ͸Client༻CodeGen Tool͕طʹز͔ͭଘࡏ͍ͯ͠Δ - https://github.com/apollographql/apollo-tooling - https://graphql-code-generator.com

Slide 7

Slide 7 text

ts-graphql-plugin - https://github.com/Quramy/ts-graphql-plugin - ๻͕ࣗ࡞͍ͯ͠ΔπʔϧɻTypeScriptͰͷClient։ൃʹಛԽ͍ͯ͠Δ - CodeGenҎ֎ʹҎԼͷػೳ΋: - GarphQL queryʹର͢ΔLanguage Service(ิ׬΍ΤϥʔνΣοΫ) - Ϗϧυ࣌ʹqueryΛparse͢ΔͨΊͷwebpack plugin - etc…

Slide 8

Slide 8 text

ͳͥCodeGenΛࣗ࡞ͨ͠ͷ͔ - ͿͬͪΌ͚Δͱʮ࡞Γ͔͔ͨͬͨΒʯͱ͍͏ͷ͕ຊԻ - ΋ͱ΋ͱApollo ToolingΛར༻͍͕ͯͨ͠ɺόʔδϣϯΞοϓʹରͯ͠ಈ ࡞͕ෆ҆ఆʹײ͍ͯͨ͡ - Apollo Toolingʹdependencies͕ଟ͗͢Δ - ts-graphql-plugin͸ 3 dependenciesͷΈʢ͔͠΋಺༁2ͭ͸graphql ͱtypescriptʣɻΊͬͪΌinstall ͍ܰ

Slide 9

Slide 9 text

ͳͥCodeGenΛࣗ࡞ͨ͠ͷ͔ - ๻ͷ৔߹ɺClientͱͯ͠͸TypeScriptͷΈ͕͋Ε͹ॆ෼ - ൚༻తͳCodeGenΛ࡞Ζ͏ͱ͢Δͱɺಈ࡞ݴޠΛந৅Խ͢ΔͨΊʹ Template Engineʢ࣮ࡍɺgraphql-codegen ͸Template Literal String ϕʔεͷpluginػߏʹͳͬͯͨϋζʣʹཔͬͯ͠·͍͕ͪ - ʮTypeScriptͷίʔυΛੜ੒͢Δ͜ͱʯΛ໨తʹ͢ΔͱɺTypeScript ASTͷAPIͰ׬݁͢Δɻ ಛʹGraphQLͷΑ͏ͳ࠶ؼߏจΛѻ͏্Ͱ͸ɺAST APIΛ৮ͬͨํ͕γ ϯϓϧʹ࡞ΕΔ

Slide 10

Slide 10 text

ࣗ࡞CodeGen - ࠓ೔͸ં֯ͷػձͳͷͰɺࣗ࡞CodeGen (ਖ਼֬ʹ͸TS Type Generation) ͷ࡞ΓํΛ঺հ

Slide 11

Slide 11 text

GraphQL visitor - queryͷղੳʹඞཁͳπʔϧ͸NPMͷ graphql ʹ ͢΂ͯAPI͕ἧ͍ͬͯΔ - parser, visitor, unperser(generator), etc… - visitorͷAPI͸ESLint΍Babel pluginͱಉ༷ͷܗ ࣜʢNode kindʹcallback͕൓Ԡ͢ΔλΠϓʣ - ֤callbackʹ౉͞ΕΔnode͸਌node৘ใΛอ ͍࣋ͯ͠ͳ͍ (non-recursive, serializableʣ import { parse, visit, DocumentNode } from 'graphql'; const inputString = ` query MyQuery { viewer { id name } } `; const documentNode = parse(inputString); visit(documentNode, { // GraphQL ASTͷNodeछผ OperationDefinition: { enter: node => { // enter ͸visitor͕nodeʹೖͬͨͱ͖ͷॲཧ if (node.operation === 'query') { console.log(node.name?.value); } }, leave: node => { // leave͸visitor͕nodeΛग़Δͱ͖ͷॲཧ }, }, });

Slide 12

Slide 12 text

ΈΜͳେ޷͖IUUQTBTUFYQMPSFSOFUͰݟΔͱ͜Μͳײ͡

Slide 13

Slide 13 text

ίʔυੜ੒ઓུ 1. GraphQL ASTͷछผຖʹɺੜ੒͞ΕΔ΂͖TypeScript ASTͷϚοϐ ϯάΛߦ͏ 2. VisitorͷCall Stackʹ߹ΘͤͯɺඞཁͳσʔλͷStackΛ༻ҙ͢Δ

Slide 14

Slide 14 text

ίʔυੜ੒ઓུ 1. GraphQL ASTͷछผຖʹɺੜ੒͞ΕΔ΂͖TypeScript ASTͷϚοϐ ϯάΛߦ͏ 2. VisitorͷCall Stackʹ߹ΘͤͯɺඞཁͳσʔλͷStackΛ༻ҙ͢Δ

Slide 15

Slide 15 text

query MyQuery { viewer { id: userId name } } export type MyQuery = { viewer: { userId: string; name: string; }; }; αϯϓϧͱͯ͠ɺ͜ͷRVFSZUZQFੜ੒ʹ͍ͭͯੜ੒نଇΛߟ͑ͯΈΔ

Slide 16

Slide 16 text

5ZQF4DSJQUͷ"45͸IUUQTUTBTUWJFXFSDPNͰ֬ೝ͢Δͷ͕Φεεϝ ίʔυੜ੒ʹඞཁͳϝιου໊ͱ͔΋ڭ͑ͯ͘ΕΔ

Slide 17

Slide 17 text

query MyQuery { viewer { id: userId name } } OperationDefinition export type MyQuery = { viewer: { userId: string; name: string; }; }; TypeAliasDeclaration OperationDefinition͸TypeAliasDeclarationʹରԠ

Slide 18

Slide 18 text

query MyQuery { viewer { id: userId name } } OperationDefinition SelectionSet export type MyQuery = { viewer: { userId: string; name: string; }; }; TypeAliasDeclaration TypeLiteral SelectionSet͸TypeLiteralʹରԠ

Slide 19

Slide 19 text

query MyQuery { viewer { id: userId name } } OperationDefinition SelectionSet Field export type MyQuery = { viewer: { userId: string; name: string; }; }; TypeAliasDeclaration TypeLiteral PropertySignature Field͸PropertySignatureʹରԠ

Slide 20

Slide 20 text

query MyQuery { viewer { id: userId name } } OperationDefinition SelectionSet Field SelectionSet export type MyQuery = { viewer: { userId: string; name: string; }; }; TypeAliasDeclaration TypeLiteral TypeLiteral PropertySignature SelectionSet͸TypeLiteralʹରԠʢ͖ͬ͞ͱҰॹʂʣ

Slide 21

Slide 21 text

query MyQuery { viewer { id: userId name } } OperationDefinition SelectionSet Field Field SelectionSet export type MyQuery = { viewer: { userId: string; name: string; }; }; TypeAliasDeclaration TypeLiteral TypeLiteral PropertySignature PropertySignature Field͸PropertySignatureʹରԠʢ͖ͬ͞ͱҰॹʂʣ

Slide 22

Slide 22 text

query MyQuery { viewer { id: userId name } } OperationDefinition SelectionSet Field Field Field SelectionSet export type MyQuery = { viewer: { userId: string; name: string; }; }; TypeAliasDeclaration TypeLiteral TypeLiteral PropertySignature PropertySignature PropertySignature OperationDefiniton -> TypeAliasDeclaration SelectionSet -> TypeLiteral Field -> PropertySignature ͨͬͨͭʢొ৔͍ͯͨ͠"45ͷछྨʣͷنଇ͚ͩͰ੒Γཱͭ

Slide 23

Slide 23 text

ίʔυੜ੒ઓུ 1. GraphQL ASTͷछผຖʹɺੜ੒͞ΕΔ΂͖TypeScript ASTͷϚοϐ ϯάΛߦ͏ 2. VisitorͷCall Stackʹ߹ΘͤͯɺඞཁͳσʔλͷStackΛ༻ҙ͢Δ

Slide 24

Slide 24 text

visitதʹඞཁͱͳΔσʔλ - ʮੜ੒نଇΛຬͨͨ͢Ίʹɺvisitor͔Βࢀর͢΂͖σʔλ͸Կ͔ʯΛߟ ͑Δ - ࠓճͷྫͩͱɺԼهͳͲΛݕ౼͢Δ - visitor͕ண໨͍ͯ͠ΔGraphQLͷSchema Object Type - visitor͕ண໨͍ͯ͠ΔFieldͷܕͱͳΔ΂͖TypeScript AST - visitor͕ண໨͍ͯ͠ΔSelectionSetʹؚ·ΕΔmemberͷܕ

Slide 25

Slide 25 text

Schema Info Stack (GraphQL Object type) Type Literal Members Stack (TypeScript AST) undefined Current Field Type (TypeScript AST) FNQUZ FNQUZ ண໨͍ͯ͠ΔGraphQLͷ Schema Object Type ண໨͍ͯ͠ΔFieldͷܕͱͳ Δ΂͖TypeScript AST ண໨͍ͯ͠ΔSelectionSetʹ ؚ·ΕΔmemberͷܕ

Slide 26

Slide 26 text

visitorͷઃܭ - enter/leave ܗࣜͷvisitorͰ͸ɺྑ͘࢖ΘΕΔ࣮૷ύλʔϯ͕͋Δ - context(stack)ʹσʔλΛ٧ΊΔͷ͸nodeʹೖΔʢenter͢Δʣͱ͖ - ੜ੒࣌ʹࢀর͍ͨ͠৘ใΛ٧ΊΕ͹͍͍ - ࣮ࡍʹੜ੒نଇΛద༻͢Δͷ͸nodeΛൈ͚Δʢleave͢Δʣͱ͖

Slide 27

Slide 27 text

Enter OperationDefinition Schema Info Stackʹ2VFSZ.VUBUJPO4VCTDSJQUJPOͷ4DIFNB৘ใΛੵΉ Leave OperationDefinition Schema Info StackΛQPQ͢Δ Current Field Type ͔ΒTypeAliasDeclarationΛੜ੒͢Δ Enter SelectionSet Type Literal Members Stackʹۭ഑ྻΛੵΉ Leave SelectionSet Type Literal MembersΛQPQ͢Δ QPQͨ͠NFNCFS৘ใ͔ΒLiteralTypeOPEFΛੜ੒ͯ͠ɺCurrent Field Type ʹηοτ͢Δ Enter Field 4DIFNB*OGP4UBDLʹͦͷpFMEʹରԠ͢Δ4DIFNB0CKFDUͷ৘ใΛੵΉ ϑΟʔϧυ͕4DBMBUZQFͷ৔߹ Current Field Typeʹ4DBMBʹରԠ͢Δܕͷ"45 Ληοτ͢Δ Leave Field 4DIFNB*OGP4UBDLΛQPQ͢Δ $VSSFOU'JFME5ZQFΛܕͱͯ࣋ͭ͠Α͏ʹQSPQFSUZ4JHOBUVSFOPEFΛੜ੒͠ɺ -JUFSBM.FNCFST4UBDLͷUBJMཁૉʹ௥Ճ ϧʔϧΛॻ͖ग़͢ͱ্هͷΑ͏ʹͳΔ͕ɺ۩ମతʹWJTJUPSͷಈ͖Λݟͨํ͕ཧղ͠΍͍͢

Slide 28

Slide 28 text

Schema Info Stack (GraphQL Object type) Type Literal Members Stack (TypeScript AST) undefined enter OperationDefinition enter SelectionSet enter Field enter SelectionSet enter Field leave Field enter Field leave Field leave SelectionSet leave Field leave SelectionSet leave OperationDefinition Current Field Type (TypeScript AST) query MyQuery { viewer { id: userId name } } FNQUZ FNQUZ ண໨͍ͯ͠ΔGraphQLͷ Schema Object Type ண໨͍ͯ͠ΔFieldͷܕͱͳ Δ΂͖TypeScript AST ண໨͍ͯ͠ΔSelectionSetʹ ؚ·ΕΔmemberͷܕ

Slide 29

Slide 29 text

type Query, name = MyQuery Schema Info Stack (GraphQL Object type) Type Literal Members Stack (TypeScript AST) undefined QVTI enter OperationDefinition enter SelectionSet enter Field enter SelectionSet enter Field leave Field enter Field leave Field leave SelectionSet leave Field leave SelectionSet leave OperationDefinition Current Field Type (TypeScript AST) query MyQuery { viewer { id: userId name } } OperationDefinition FNQUZ

Slide 30

Slide 30 text

type Query, name = MyQuery Schema Info Stack (GraphQL Object type) Type Literal Members Stack (TypeScript AST) [] undefined enter OperationDefinition enter SelectionSet enter Field enter SelectionSet enter Field leave Field enter Field leave Field leave SelectionSet leave Field leave SelectionSet leave OperationDefinition Current Field Type (TypeScript AST) query MyQuery { viewer { id: userId name } } SelectionSet QVTI

Slide 31

Slide 31 text

type Query, name = MyQuery Schema Info Stack (GraphQL Object type) Type Literal Members Stack (TypeScript AST) [] type Viewer!, name = viewer undefined QVTI enter OperationDefinition enter SelectionSet enter Field enter SelectionSet enter Field leave Field enter Field leave Field leave SelectionSet leave Field leave SelectionSet leave OperationDefinition Current Field Type (TypeScript AST) query MyQuery { viewer { id: userId name } } Field

Slide 32

Slide 32 text

type Query, name = MyQuery Schema Info Stack (GraphQL Object type) Type Literal Members Stack (TypeScript AST) [] type Viewer!, name = viewer [] undefined enter OperationDefinition enter SelectionSet enter Field enter SelectionSet enter Field leave Field enter Field leave Field leave SelectionSet leave Field leave SelectionSet leave OperationDefinition Current Field Type (TypeScript AST) query MyQuery { viewer { id: userId name } } SelectionSet QVTI

Slide 33

Slide 33 text

type Query, name = MyQuery Schema Info Stack (GraphQL Object type) Type Literal Members Stack (TypeScript AST) [] type Viewer!, name = viewer [] string type ID!, name = userId QVTI enter OperationDefinition enter SelectionSet enter Field enter SelectionSet enter Field leave Field enter Field leave Field leave SelectionSet leave Field leave SelectionSet leave OperationDefinition Current Field Type (TypeScript AST) query MyQuery { viewer { id: userId name } } Field

Slide 34

Slide 34 text

type Query, name = MyQuery Schema Info Stack (GraphQL Object type) Type Literal Members Stack (TypeScript AST) [] type Viewer!, name = viewer [userId: string;] string type ID!, name = userId QPQ enter OperationDefinition enter SelectionSet enter Field enter SelectionSet enter Field leave Field enter Field leave Field leave SelectionSet leave Field leave SelectionSet leave OperationDefinition Current Field Type (TypeScript AST) query MyQuery { viewer { id: userId name } } Field

Slide 35

Slide 35 text

type Query, name = MyQuery Schema Info Stack (GraphQL Object type) Type Literal Members Stack (TypeScript AST) [] type Viewer!, name = viewer [userId: string;] string type String!, name = name QVTI enter OperationDefinition enter SelectionSet enter Field enter SelectionSet enter Field leave Field enter Field leave Field leave SelectionSet leave Field leave SelectionSet leave OperationDefinition Current Field Type (TypeScript AST) query MyQuery { viewer { id: userId name } } Field

Slide 36

Slide 36 text

type Query, name = MyQuery Schema Info Stack (GraphQL Object type) Type Literal Members Stack (TypeScript AST) [] type Viewer!, name = viewer [userId: string; name: string;] string type String!, name = name QPQ enter OperationDefinition enter SelectionSet enter Field enter SelectionSet enter Field leave Field enter Field leave Field leave SelectionSet leave Field leave SelectionSet leave OperationDefinition Current Field Type (TypeScript AST) query MyQuery { viewer { id: userId name } } Field

Slide 37

Slide 37 text

type Query, name = MyQuery Schema Info Stack (GraphQL Object type) Type Literal Members Stack (TypeScript AST) [] type Viewer!, name = viewer [userId: string; name: string;] { userId: string; name: string; } enter OperationDefinition enter SelectionSet enter Field enter SelectionSet enter Field leave Field enter Field leave Field leave SelectionSet leave Field leave SelectionSet leave OperationDefinition Current Field Type (TypeScript AST) query MyQuery { viewer { id: userId name } } SelectionSet QPQ

Slide 38

Slide 38 text

type Query, name = MyQuery Schema Info Stack (GraphQL Object type) Type Literal Members Stack (TypeScript AST) [viwer: {…}] type Viewer!, name = viewer { userId: string; name: string; } QPQ enter OperationDefinition enter SelectionSet enter Field enter SelectionSet enter Field leave Field enter Field leave Field leave SelectionSet leave Field leave SelectionSet leave OperationDefinition Current Field Type (TypeScript AST) query MyQuery { viewer { id: userId name } } Field

Slide 39

Slide 39 text

type Query, name = MyQuery Schema Info Stack (GraphQL Object type) Type Literal Members Stack (TypeScript AST) [viwer: {…}] { viewer: { userId: string; name: string; }; } enter OperationDefinition enter SelectionSet enter Field enter SelectionSet enter Field leave Field enter Field leave Field leave SelectionSet leave Field leave SelectionSet leave OperationDefinition Current Field Type (TypeScript AST) query MyQuery { viewer { id: userId name } } SelectionSet QPQ

Slide 40

Slide 40 text

type Query, name = MyQuery Schema Info Stack (GraphQL Object type) Type Literal Members Stack (TypeScript AST) { viewer: { userId: string; name: string; }; } QPQ enter OperationDefinition enter SelectionSet enter Field enter SelectionSet enter Field leave Field enter Field leave Field leave SelectionSet leave Field leave SelectionSet leave OperationDefinition Current Field Type (TypeScript AST) $VSSFOU'JFME5ZQFͱ4DIFNB*OGP4UBDLͷઌ಄͔ΒUZQFΛPVUQVUͰ͖Δ query MyQuery { viewer { id: userId name } } OperationDefinition FNQUZ

Slide 41

Slide 41 text

AST to ASTͷ୉ޣຯ - ͘͝؆୯ͳྫͰղઆ͕ͨ͠ɺts-graphql-pluginͰ΍͍ͬͯΔͷ΋ղઆ͠ ͨύλʔϯͱҰॹ - ୯७ͳϧʔϧͳ૊Έ߹ΘͤͰෳࡶͳܕ͕ੜ੒Ͱ͖Δͷ͸ຊ౰ʹ໘ന͍ - e.g. Current Field Type͔ΒType Literal MembersΛੜ੒͢Δࡍʹͪΐͬͱͨ͠ॲཧΛ௥Ճ ͢Δɻ Current Field TypeʹͲΜͳܕ͕ೖ͍ͬͯͯ΋੒Γཱͭ - ts.SyntaxKind.NullKeyword ΛՃ͑ͯ ts.createUnionTypeNode ΛऔΕ͹ɺ Optionalͳܕͷදݱʹ - ts.createArrayTypeNode Ͱϥοϓ͢Ε͹ɺ഑ྻܕͷදݱʹ

Slide 42

Slide 42 text

Summary - GraphQL AST͔ΒTypeScriptͷASTΛੜ੒͢ΔྲྀΕΛղઆ - ʮ͘͝؆୯ͳϧʔϧͷ૊Έ߹ΘͤͰෳࡶͳίʔυΛੜ੒͢Δʯͱ͍͏ҙ ຯͰ͸ɺίϯύΠϥͷ࣮૷ͱࣅ͍ͯΔͱ͜Ζ͕͋Δ - GraphQLͷAST͸ඇৗʹγϯϓϧͳͷͰɺࣗ෼ͷཉ͍͠ίʔυʹ߹Θ ͤͯCodeGenΛख૊Έ͢Δͱָ͍͠ - Apollo Link΍apollo-client΋಺෦తʹGraphQL ͷvisitorΛར༻͢Δͨ Ίɺ஌ࣝͷԠ༻΋ޮ͘

Slide 43

Slide 43 text

Thank you!