【问题标题】:graphql-codegen dynamic fields with interpolation带有插值的 graphql-codegen 动态字段
【发布时间】:2020-10-26 05:03:48
【问题描述】:

我正在使用 graphql-codegen 从 graphql 模式生成打字稿类型。我正在尝试使用动态字段创建片段。

schema.ts

这是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

我在整个应用程序中使用这些接口进行验证和一致性。

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

这是用于生成的文件。在这里,我想使用我现有的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 UserProfileQuery($id: String!) {
      showUser(id: $id) {
        ...UserProfile
      }
    }
`;

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

当我尝试使用插值传递这些字段时,我收到此错误:

$ 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

发现 1 个错误

× C:/Development/GogoFans/gogofans-ui/src/app/users/graphql/fragments/show.ts
GraphQLError:语法错误:预期名称,找到“}”。

在 syntaxError (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\error\syntaxError.js:15:10)
在 Parser.expectToken (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:1423:40)
在 Parser.parseName (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:92:22)
在 Parser.parseField (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:289:28)
在 Parser.parseSelection (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:278:81)
在 Parser.many (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:1537:26)
在 Parser.parseSelectionSet (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:265:24)
在 Parser.parseFragmentDefinition (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:410:26)
在 Parser.parseDefinition (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:134:23)
在 Parser.many (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:1537:26)
在 Parser.parseDocument (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:109:25)
在 Object.parse (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:36:17)
在 Object.parseGraphQLSDL (C:\Development\GogoFans\gogofans-ui\node_modules@graphql-tools\utils\index.cjs.js:601:28)
在 parseSDL (C:\Development\GogoFans\gogofans-ui\node_modules@graphql-tools\code-file-loader\index.cjs.js:239:18)
在 CodeFileLoader.load (C:\Development\GogoFans\gogofans-ui\node_modules@graphql-tools\code-file-loader\index.cjs.js:173:28)
在异步加载文件(C:\Development\GogoFans\gogofans-ui\node_modules@graphql-tools\load\index.cjs.js:48:24)

GraphQLError:语法错误:预期名称,找到“}”。

在 syntaxError (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\error\syntaxError.js:15:10)
在 Parser.expectToken (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:1423:40)
在 Parser.parseName (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:92:22)
在 Parser.parseField (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:289:28)
在 Parser.parseSelection (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:278:81)
在 Parser.many (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:1537:26)
在 Parser.parseSelectionSet (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:265:24)
在 Parser.parseFragmentDefinition (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:410:26)
在 Parser.parseDefinition (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:134:23)
在 Parser.many (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:1537:26)
在 Parser.parseDocument (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:109:25)
在 Object.parse (C:\Development\GogoFans\gogofans-ui\node_modules\graphql\language\parser.js:36:17)
在 Object.parseGraphQLSDL (C:\Development\GogoFans\gogofans-ui\node_modules@graphql-tools\utils\index.cjs.js:601:28)
在 parseSDL (C:\Development\GogoFans\gogofans-ui\node_modules@graphql-tools\code-file-loader\index.cjs.js:239:18)
在 CodeFileLoader.load (C:\Development\GogoFans\gogofans-ui\node_modules@graphql-tools\code-file-loader\index.cjs.js:173:28)
在异步加载文件(C:\Development\GogoFans\gogofans-ui\node_modules@graphql-tools\load\index.cjs.js:48:24)

出了点问题

npm 错误!代码生命周期
npm 错误!错误号 1
npm 错误! gogofans-ui@0.0.0 生成:graphql-codegen --config codegen.yml
npm 错误!退出状态 1
npm 错误!
npm 错误! gogofans-ui@0.0.0 生成脚本失败。
npm 错误!这可能不是 npm 的问题。上面可能还有额外的日志输出。

npm 错误!可以在以下位置找到此运行的完整日志:
npm 错误! C:\Users\Fidel\AppData\Roaming\npm-cache_logs\2020-07-06T07_01_25_424Z-debug.log

【问题讨论】:

    标签: angular typescript graphql graphql-tag graphql-codegen


    【解决方案1】:

    GraphQL codegen 使用代码 AST 来查找操作(使用 graphql-tag-pluck)。它不进行字符串插值,因为在某些情况下,它仅在应用程序运行时确定,或者它可能是 codegen 无法真正访问的内部变量。

    为了运行字符串插值 - 我们需要编译和运行你的代码文件,这不是 codegen 真正能做的事情。

    为什么需要进行字符串插值?你能解释一下你的用例吗?因为如果它用于分隔字段列表 - 然后使用 GraphQL 片段。如果是动态更改字段集 - 使用内置的 @skip@include 指令。 如果您仍需要对 codegen 加载文档的方式进行更多控制,请使用自定义文档加载器:https://graphql-code-generator.com/docs/getting-started/documents-field#custom-document-loader

    在我看来,使用 .graphql 文件进行 GraphQL 操作会更简单,并让 codegen 使用 typescripttypescript-operationstypescript-apollo-angular 插件生成即用型代码 - 这样你就得到了Angular Services,基于你的操作,它是完全类型安全的,GraphQL 操作已经在里面定义了。

    【讨论】:

    • 我编辑了我的问题,但基本上我想使用插值从我的界面动态添加字段,这样可以避免字段重复。
    【解决方案2】:

    因为您的架构是静态的,所以字段不会改变。这意味着,您可以将所有可能的字段添加到您的选择集中,然后使用@skip@include 指令对其进行过滤。

    GraphQL Codegen 及其使用的工具不支持字符串插值,也不会添加对它的支持,因为为了获得最终字符串,我们需要加载、编译和查找导出的标识符.这样做会使 codegen 的设置变得更加复杂 - 因为 JS 生态系统中有多种风格。

    GraphQL 架构和操作可以定义为静态字符串,您应该能够使用指令或类似操作动态控制选择集。

    下面是使用内置 @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
    }
    

    这样,您可以在运行时通过在您的 JS 代码中设置变量 $loadA$loadB 来动态控制它。

    这些指令的定义与 GraphQL 中的类似:

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

    这意味着您可以在字段、片段扩展或内联片段上使用它 - 因此它应该为您提供足够的灵活性来管理复杂和动态的选择集。

    【讨论】:

      猜你喜欢
      • 2019-11-09
      • 2020-01-30
      • 2021-04-06
      • 1970-01-01
      • 2021-04-07
      • 2019-05-08
      • 2018-02-01
      • 1970-01-01
      • 2020-03-03
      相关资源
      最近更新 更多