简体   繁体   English

带有插值的 graphql-codegen 动态字段

[英]graphql-codegen dynamic fields with interpolation

I'm using graphql-codegen to generate typescript types from graphql schema.我正在使用graphql- codegen 从 graphql 模式生成 typescript 类型。 I'm trying to create a fragment with dynamic fields.我正在尝试创建一个带有动态字段的片段。

schema.ts架构.ts

This is the type generated by graphql-codegen .这是graphql-codegen生成的类型。

/** User Type */
export type UserType = {
  __typename?: 'UserType';
  id: Scalars['ID'];
  avatar: Scalars['String'];
  email: Scalars['String'];
  name: Scalars['String'];
  showPostsInFeed: Scalars['Boolean'];
  username: Scalars['String'];
};

user.model.ts用户.model.ts

I'm using these interfaces throughout the entire application for validations and consistency.我在整个应用程序中使用这些接口进行验证和一致性。

export interface IUserBase {
  id: string;
  avatar: string;
  name: string;
  username: string;
}

export interface IUserPost extends IUserBase {
  showPostsInFeed: boolean;
}

export interface IUserProfile extends IUserBase, IUserPost {
  email: string;
}

show.ts show.ts

This is the file used for generation.这是用于生成的文件。 Here I want to make a fragment with dynamic fields using my existent IUserPost and IUserProfile interfaces, in order to reuse those fields and avoid duplication repeating them inside the fragment one by one.在这里,我想使用我现有IUserPostIUserProfile接口制作一个带有动态字段的片段,以便重用这些字段并避免在片段中一一重复它们。

import gql from 'graphql-tag';
import { keys } from 'ts-transformer-keys';

import { IUserProfile, IUserPost } from '../../user.model';

const keysUserPofile = keys<IUserProfile>();  //Get all interface keys
const keysUserPost = keys<IUserPost>();  //Get all interface keys

//Fragments
export const fragments = {
  userProfile: gql`
    fragment UserProfile on UserType {
      ${keysUserPofile.join('\n')}    //Interpolation
    }
  `,
  userPost: gql`
    fragment UserPost on UserType {
      ${keysUserPost.join('\n')}    //Interpolation
    }
  `
};

//Queries
export const userProfileQuery = gql`
    query UserProfileQuey($id: String!) {
      showUser(id: $id) {
        ...UserProfile
      }
    }
`;

export const userPostQuery = gql`
    query UserPostQuey($id: String!) {
      showUser(id: $id) {
        ...UserPost
      }
    }
`;

When I try to pass these fields using interpolation, I get this error.当我尝试使用插值传递这些字段时,出现此错误。

$ npm run generate

> gogofans-ui@0.0.0 generate C:\Development\GogoFans\gogofans-ui
> graphql-codegen --config codegen.yml

  √ Parse configuration
  > Generate outputs
    > Generate src/app/core/graphql/schema.ts
      √ Load GraphQL schemas
      × Load GraphQL documents
        → Syntax Error: Expected Name, found "}".
        Generate


 Found 1 error

  × C:/Development/GogoFans/gogofans-ui/src/app/users/graphql/fragments/show.ts
    GraphQLError: Syntax Error: Expected Name, found "}".
        at syntaxError (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\error\syntaxError.js:15:10)
        at Parser.expectToken (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:1423:40)     
        at Parser.parseName (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:92:22)
        at Parser.parseField (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:289:28)       
        at Parser.parseSelection (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:278:81)   
        at Parser.many (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:1537:26)
        at Parser.parseSelectionSet (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:265:24)
        at Parser.parseFragmentDefinition (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:410:26)
        at Parser.parseDefinition (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:134:23)     
        at Parser.many (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:1537:26)
        at Parser.parseDocument (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:109:25)       
        at Object.parse (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:36:17)
        at Object.parseGraphQLSDL (C:\Development\GogoFans\gogofans-ui\node_modules\@graphql-tools\utils\index.cjs.js:601:28)
        at parseSDL (C:\Development\GogoFans\gogofans-ui\node_modules\@graphql-tools\code-file-loader\index.cjs.js:239:18) 
        at CodeFileLoader.load (C:\Development\GogoFans\gogofans-ui\node_modules\@graphql-tools\code-file-loader\index.cjs.js:173:28)
        at async loadFile (C:\Development\GogoFans\gogofans-ui\node_modules\@graphql-tools\load\index.cjs.js:48:24)        
    GraphQLError: Syntax Error: Expected Name, found "}".
        at syntaxError (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\error\syntaxError.js:15:10)
        at Parser.expectToken (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:1423:40)        
        at Parser.parseName (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:92:22)
        at Parser.parseField (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:289:28)
        at Parser.parseSelection (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:278:81)      
        at Parser.many (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:1537:26)
        at Parser.parseSelectionSet (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:265:24)   
        at Parser.parseFragmentDefinition (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:410:26)
        at Parser.parseDefinition (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:134:23)     
        at Parser.many (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:1537:26)
        at Parser.parseDocument (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:109:25)       
        at Object.parse (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:36:17)
        at Object.parseGraphQLSDL (C:\Development\GogoFans\gogofans-ui\node_modules\@graphql-tools\utils\index.cjs.js:601:28)
        at parseSDL (C:\Development\GogoFans\gogofans-ui\node_modules\@graphql-tools\code-file-loader\index.cjs.js:239:18) 
        at CodeFileLoader.load (C:\Development\GogoFans\gogofans-ui\node_modules\@graphql-tools\code-file-loader\index.cjs.js:173:28)
        at async loadFile (C:\Development\GogoFans\gogofans-ui\node_modules\@graphql-tools\load\index.cjs.js:48:24)        


Something went wrong
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! gogofans-ui@0.0.0 generate: `graphql-codegen --config codegen.yml`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the gogofans-ui@0.0.0 generate script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\Fidel\AppData\Roaming\npm-cache\_logs\2020-07-06T07_01_25_424Z-debug.log

GraphQL codegen is using code AST to look for operations (using graphql-tag-pluck). GraphQL 代码生成正在使用代码 AST 来查找操作(使用 graphql-tag-pluck)。 It doesn't do string interpolations, because in some cases it's something that is being determined only at runtime of your application, or it might be an internal variable that codegen can't really access.它不进行字符串插值,因为在某些情况下,它仅在应用程序运行时确定,或者它可能是 codegen 无法真正访问的内部变量。

In order to run the string interpolation - we need to compile and run your code file, and it's not something that codegen can really do.为了运行字符串插值 - 我们需要编译和运行你的代码文件,这不是 codegen 真正可以做的事情。

Why do you need to do string interpolation?为什么需要进行字符串插值? can you please explain your use case?你能解释一下你的用例吗? Because if it's for separating the list of fields - then use GraphQL fragments.因为如果它用于分隔字段列表 - 然后使用 GraphQL 片段。 If it's for dynamically change the fields set - use the built-in @skip and @include directives.如果是动态更改字段集 - 使用内置的@skip@include指令。 If you still need more control over the way codegen loads your documents, use custom document loader: https://graphql-code-generator.com/docs/getting-started/documents-field#custom-document-loader如果您仍需要对 codegen 加载文档的方式进行更多控制,请使用自定义文档加载器: https://graphql-code-generator.com/docs/getting-started/documents-field#custom-document-loader

In my opinion, it's simpler to use .graphql files for your GraphQL operations, and let codegen generate a ready-to-use code with typescript , typescript-operations and typescript-apollo-angular plugins - this way you are getting Angular Service s, based on your operations, and it's fully type-safe, and the GraphQL operation is already defined inside. In my opinion, it's simpler to use .graphql files for your GraphQL operations, and let codegen generate a ready-to-use code with typescript , typescript typescript-operations and typescript typescript-apollo-angular plugins - this way you are getting Angular Service s,根据您的操作,它是完全类型安全的,并且 GraphQL 操作已在内部定义。

Because you schema is static, fields are not going to change.因为您的架构是 static,所以字段不会更改。 That means, that you can add all possible fields to your selection set, and later filter it by using @skip or @include directives.这意味着,您可以将所有可能的字段添加到您的选择集中,然后使用@skip@include指令对其进行过滤。

GraphQL Codegen and the tooling it uses doesn't support string interpolation, and it's not going to add support for it, because in order to get the final string, we'll need to load, compile and look for that exported identifier. GraphQL Codegen 及其使用的工具不支持字符串插值,也不会添加对它的支持,因为为了获得最终的字符串,我们需要加载、编译并查找导出的标识符。 Doing that will make the setup of codegen much more complex - because of the many flavours in the JS ecosystem.这样做会使 codegen 的设置变得更加复杂——因为 JS 生态系统中有许多不同的风格。

GraphQL schema and operations could be defined as static strings, and you should be able to control the selection set dynamically with directives or similar manipulations. GraphQL 架构和操作可以定义为 static 字符串,您应该能够使用指令或类似操作动态控制选择集。

Here's an example for using the built-in @skip and @include directives, over a fragment spread:下面是一个使用内置@skip@include指令的示例,在片段传播中:

query UserProfileQuery($id: String!, $loadA: Boolean, $loadB: Boolean) {
      showUser(id: $id) {
        ...UserFieldsA @include(if: $loadA)
        ...UserFieldsB @include(if: $loadB)
      }
    }

fragment UserFieldsA {
  id
  a
}

fragment UserFieldsB {
  id
  b
}

This way, you can control it dynamically, by setting the variables $loadA or $loadB from your JS code, during runtime.这样,您可以在运行时通过在 JS 代码中设置变量$loadA$loadB来动态控制它。

These directives are defined like that in GraphQL:这些指令的定义类似于 GraphQL 中的定义:

directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT

directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT

That means you can use it over a field, fragment spread or an inline fragment - so it should give you enough flexibility to manage complex and dynamic selection sets.这意味着您可以在字段、片段扩展或内联片段上使用它——因此它应该为您提供足够的灵活性来管理复杂和动态的选择集。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM