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

DIY GraphQL Codegen

DIY GraphQL Codegen

893f54413c2bd9ba41d11d753aacaf2c?s=128

Yosuke Kurami

August 28, 2020
Tweet

Transcript

  1. DIY GraphQL Code Generation GraphQL Tokyo 2020.08.28

  2. Client Side Code Generation - ͳͥGraphQLͰCodeGen͕ඞཁͳͷ͔ - ClientͷϦΫΤετ(query)ͷܗʹԠͯ͡Response͕ܾఆ͞ΕΔͷ͕ GraphQLͷಛ௃ -

    ಛʹ੩తܕ෇ݴޠͷ৔߹ʮͲͷΑ͏ͳσʔλ͕ฦͬͯ͘Δ͔ʯ͕ඞཁ ʹͳΔ
  3. Client Side Code Generation export default () => { const

    { data } = useQuery< GitHubQuery, GitHubQueryVariables >(query, { variables: { first: 100 } }); if (!data) return null; return ( <ul> {data.viewer?.repositories?.nodes?.map(repo => ( <li key={repo?.id}> <span>{repo?.description}</span> </li> ))} </ul> ); }; const repositoryFragment = gql` fragment RepositoryFragment on Repository { description } `; const query = gql` ${repositoryFragment} query GitHubQuery($first: Int!) { viewer { repositories(first: $first) { nodes { id ...RepositoryFragment } } } } `;
  4. 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; };
  5. Client Side Code Generation - queryʹଘࡏ͠ͳ͍ϑΟʔϧυʹରͯ͠ɺίʔυ͔ΒͷΞΫηεΛېࢭͰ ͖ΔͨΊɺCodeGen͸ʮUnder FetchingΛ๷ࢭ͢Δ࢓૊Έʯͱߟ͑Δ͜ ͱ΋Ͱ͖Δ -

    ※ Under Fetching: ຊདྷClientʹඞཁͳϑΟʔϧυΛqueryʹॻ͖๨Εͯ͠·͏͜ͱɻ ػೳཁ্݅ͷෆඋʹͳΔɻ ରͱͳΔͷ͸ Over FetchingɻෆཁͳϑΟʔϧυ͕queryʹࡌ͍ͬͯΔঢ়ଶɻੑೳྼ ԽΛҾ͖ى͜͢ɻඇػೳཁ݅ͷෆඋͱͳΔɻ
  6. CodeGen tools - ੈͷதʹ͸Client༻CodeGen Tool͕طʹز͔ͭଘࡏ͍ͯ͠Δ - https://github.com/apollographql/apollo-tooling - https://graphql-code-generator.com

  7. ts-graphql-plugin - https://github.com/Quramy/ts-graphql-plugin - ๻͕ࣗ࡞͍ͯ͠ΔπʔϧɻTypeScriptͰͷClient։ൃʹಛԽ͍ͯ͠Δ - CodeGenҎ֎ʹҎԼͷػೳ΋: - GarphQL queryʹର͢ΔLanguage

    Service(ิ׬΍ΤϥʔνΣοΫ) - Ϗϧυ࣌ʹqueryΛparse͢ΔͨΊͷwebpack plugin - etc…
  8. ͳͥCodeGenΛࣗ࡞ͨ͠ͷ͔ - ͿͬͪΌ͚Δͱʮ࡞Γ͔͔ͨͬͨΒʯͱ͍͏ͷ͕ຊԻ - ΋ͱ΋ͱApollo ToolingΛར༻͍͕ͯͨ͠ɺόʔδϣϯΞοϓʹରͯ͠ಈ ࡞͕ෆ҆ఆʹײ͍ͯͨ͡ - Apollo Toolingʹdependencies͕ଟ͗͢Δ

    - ts-graphql-plugin͸ 3 dependenciesͷΈʢ͔͠΋಺༁2ͭ͸graphql ͱtypescriptʣɻΊͬͪΌinstall ͍ܰ
  9. ͳͥCodeGenΛࣗ࡞ͨ͠ͷ͔ - ๻ͷ৔߹ɺClientͱͯ͠͸TypeScriptͷΈ͕͋Ε͹ॆ෼ - ൚༻తͳCodeGenΛ࡞Ζ͏ͱ͢Δͱɺಈ࡞ݴޠΛந৅Խ͢ΔͨΊʹ Template Engineʢ࣮ࡍɺgraphql-codegen ͸Template Literal String

    ϕʔεͷpluginػߏʹͳͬͯͨϋζʣʹཔͬͯ͠·͍͕ͪ - ʮTypeScriptͷίʔυΛੜ੒͢Δ͜ͱʯΛ໨తʹ͢ΔͱɺTypeScript ASTͷAPIͰ׬݁͢Δɻ ಛʹGraphQLͷΑ͏ͳ࠶ؼߏจΛѻ͏্Ͱ͸ɺAST APIΛ৮ͬͨํ͕γ ϯϓϧʹ࡞ΕΔ
  10. ࣗ࡞CodeGen - ࠓ೔͸ં֯ͷػձͳͷͰɺࣗ࡞CodeGen (ਖ਼֬ʹ͸TS Type Generation) ͷ࡞ΓํΛ঺հ

  11. 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Λग़Δͱ͖ͷॲཧ }, }, });
  12. ΈΜͳେ޷͖IUUQTBTUFYQMPSFSOFUͰݟΔͱ͜Μͳײ͡

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

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

  15. query MyQuery { viewer { id: userId name } }

    export type MyQuery = { viewer: { userId: string; name: string; }; }; αϯϓϧͱͯ͠ɺ͜ͷRVFSZUZQFੜ੒ʹ͍ͭͯੜ੒نଇΛߟ͑ͯΈΔ
  16. 5ZQF4DSJQUͷ"45͸IUUQTUTBTUWJFXFSDPNͰ֬ೝ͢Δͷ͕Φεεϝ ίʔυੜ੒ʹඞཁͳϝιου໊ͱ͔΋ڭ͑ͯ͘ΕΔ

  17. query MyQuery { viewer { id: userId name } }

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

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

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

    OperationDefinition SelectionSet Field SelectionSet export type MyQuery = { viewer: { userId: string; name: string; }; }; TypeAliasDeclaration TypeLiteral TypeLiteral PropertySignature SelectionSet͸TypeLiteralʹରԠʢ͖ͬ͞ͱҰॹʂʣ
  21. 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ʹରԠʢ͖ͬ͞ͱҰॹʂʣ
  22. 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ͷछྨʣͷنଇ͚ͩͰ੒Γཱͭ
  23. ίʔυੜ੒ઓུ 1. GraphQL ASTͷछผຖʹɺੜ੒͞ΕΔ΂͖TypeScript ASTͷϚοϐ ϯάΛߦ͏ 2. VisitorͷCall Stackʹ߹ΘͤͯɺඞཁͳσʔλͷStackΛ༻ҙ͢Δ

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

    - visitor͕ண໨͍ͯ͠ΔFieldͷܕͱͳΔ΂͖TypeScript AST - visitor͕ண໨͍ͯ͠ΔSelectionSetʹؚ·ΕΔmemberͷܕ
  25. 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ͷܕ
  26. visitorͷઃܭ - enter/leave ܗࣜͷvisitorͰ͸ɺྑ͘࢖ΘΕΔ࣮૷ύλʔϯ͕͋Δ - context(stack)ʹσʔλΛ٧ΊΔͷ͸nodeʹೖΔʢenter͢Δʣͱ͖ - ੜ੒࣌ʹࢀর͍ͨ͠৘ใΛ٧ΊΕ͹͍͍ - ࣮ࡍʹੜ੒نଇΛద༻͢Δͷ͸nodeΛൈ͚Δʢleave͢Δʣͱ͖

  27. 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ͷಈ͖Λݟͨํ͕ཧղ͠΍͍͢
  28. 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ͷܕ
  29. 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
  30. 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
  31. 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
  32. 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
  33. 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
  34. 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
  35. 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
  36. 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
  37. 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
  38. 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
  39. 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
  40. 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
  41. 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 Ͱϥοϓ͢Ε͹ɺ഑ྻܕͷදݱʹ
  42. Summary - GraphQL AST͔ΒTypeScriptͷASTΛੜ੒͢ΔྲྀΕΛղઆ - ʮ͘͝؆୯ͳϧʔϧͷ૊Έ߹ΘͤͰෳࡶͳίʔυΛੜ੒͢Δʯͱ͍͏ҙ ຯͰ͸ɺίϯύΠϥͷ࣮૷ͱࣅ͍ͯΔͱ͜Ζ͕͋Δ - GraphQLͷAST͸ඇৗʹγϯϓϧͳͷͰɺࣗ෼ͷཉ͍͠ίʔυʹ߹Θ ͤͯCodeGenΛख૊Έ͢Δͱָ͍͠

    - Apollo Link΍apollo-client΋಺෦తʹGraphQL ͷvisitorΛར༻͢Δͨ Ίɺ஌ࣝͷԠ༻΋ޮ͘
  43. Thank you!