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

DIY GraphQL Codegen

DIY GraphQL Codegen

Yosuke Kurami

August 28, 2020
Tweet

More Decks by Yosuke Kurami

Other Decks in Programming

Transcript

  1. 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 } } } } `;
  2. 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; };
  3. Client Side Code Generation - queryʹଘࡏ͠ͳ͍ϑΟʔϧυʹରͯ͠ɺίʔυ͔ΒͷΞΫηεΛېࢭͰ ͖ΔͨΊɺCodeGen͸ʮUnder FetchingΛ๷ࢭ͢Δ࢓૊Έʯͱߟ͑Δ͜ ͱ΋Ͱ͖Δ -

    ※ Under Fetching: ຊདྷClientʹඞཁͳϑΟʔϧυΛqueryʹॻ͖๨Εͯ͠·͏͜ͱɻ ػೳཁ্݅ͷෆඋʹͳΔɻ ରͱͳΔͷ͸ Over FetchingɻෆཁͳϑΟʔϧυ͕queryʹࡌ͍ͬͯΔঢ়ଶɻੑೳྼ ԽΛҾ͖ى͜͢ɻඇػೳཁ݅ͷෆඋͱͳΔɻ
  4. ͳͥCodeGenΛࣗ࡞ͨ͠ͷ͔ - ๻ͷ৔߹ɺClientͱͯ͠͸TypeScriptͷΈ͕͋Ε͹ॆ෼ - ൚༻తͳCodeGenΛ࡞Ζ͏ͱ͢Δͱɺಈ࡞ݴޠΛந৅Խ͢ΔͨΊʹ Template Engineʢ࣮ࡍɺgraphql-codegen ͸Template Literal String

    ϕʔεͷpluginػߏʹͳͬͯͨϋζʣʹཔͬͯ͠·͍͕ͪ - ʮTypeScriptͷίʔυΛੜ੒͢Δ͜ͱʯΛ໨తʹ͢ΔͱɺTypeScript ASTͷAPIͰ׬݁͢Δɻ ಛʹGraphQLͷΑ͏ͳ࠶ؼߏจΛѻ͏্Ͱ͸ɺAST APIΛ৮ͬͨํ͕γ ϯϓϧʹ࡞ΕΔ
  5. 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Λग़Δͱ͖ͷॲཧ }, }, });
  6. query MyQuery { viewer { id: userId name } }

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

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

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

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

    OperationDefinition SelectionSet Field SelectionSet export type MyQuery = { viewer: { userId: string; name: string; }; }; TypeAliasDeclaration TypeLiteral TypeLiteral PropertySignature SelectionSet͸TypeLiteralʹରԠʢ͖ͬ͞ͱҰॹʂʣ
  11. 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ʹରԠʢ͖ͬ͞ͱҰॹʂʣ
  12. 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ͷछྨʣͷنଇ͚ͩͰ੒Γཱͭ
  13. 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ͷܕ
  14. 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ͷಈ͖Λݟͨํ͕ཧղ͠΍͍͢
  15. 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ͷܕ
  16. 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
  17. 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
  18. 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
  19. 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
  20. 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
  21. 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
  22. 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
  23. 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
  24. 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
  25. 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
  26. 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
  27. 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
  28. 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 Ͱϥοϓ͢Ε͹ɺ഑ྻܕͷදݱʹ