【问题标题】:How to manage GraphQL child objectType that can be nullable in an output type?如何管理在输出类型中可以为空的 GraphQL 子对象类型?
【发布时间】:2019-06-23 01:38:50
【问题描述】:

我正在设置一个 nodeJS GraphQL API,并且我正在试验关于我的一种资源输出类型的阻塞点。

该功能是一个包含三个不同级别的表单:

  • 1 级 - 表单模板
  • 2 级 - formItems(templateId、类型(视频、图像、问题) - 与 formTemplate 的 1-N 关系)
  • 3 级 - formQuestions(当且仅当 formItems.type 为“问题”时,与 formItem 的关系为 0-1)

我的 GraphQL 资源正在返回数据库中的所有模板,因此它是一个数组,每个模板都返回他的所有项目,并且每个“问题”类型的项目都需要返回一个包含相关问题的数组。

我的问题是:我真的不知道如何为类型不同于“问题”的 formItems 返回一个空对象类型,或者对于这种情况是否有更好的方法

我尝试查看 GraphQL 指令和内联片段,但我认为它确实需要由后端管理,因为它对 API 使用者是透明的。

const formTemplate = new GraphQLObjectType({
  name: 'FormTemplate',
  fields: () => {
    return {
      id: {
        type: new GraphQLNonNull(GraphQLInt)
      },
      authorId: {
        type: new GraphQLNonNull(GraphQLInt)
      },
      name: {
        type: new GraphQLNonNull(GraphQLString)
      },
      items: {
        type: new GraphQLList(formItem),
        resolve: parent => FormItem.findAllByTemplateId(parent.id)
      }
    }
  }
})

const formItem = new GraphQLObjectType({
  name: 'FormItem',
  fields: () => {
    return {
      id: {
        type: new GraphQLNonNull(GraphQLInt)
      },
      templateId: {
        type: new GraphQLNonNull(GraphQLInt)
      },
      type: {
        type: new GraphQLNonNull(GraphQLString)
      },
      question: {
        type: formQuestion,
        resolve: async parent => FormQuestion.findByItemId(parent.id)
      }
    }
  }
})

const formQuestion= new GraphQLObjectType({
  name: 'FormQuestion',
  fields: () => {
    return {
      id: {
        type: new GraphQLNonNull(GraphQLInt)
      },
      itemId: {
        type: new GraphQLNonNull(GraphQLInt)
      },
      type: {
        type: new GraphQLNonNull(GraphQLString)
      },
      label: {
        type: new GraphQLNonNull(GraphQLString)
      }
    }
  }
})

我的 GraphQL 请求:

query {
  getFormTemplates {
    name
    items {
      type
      question {
        label
        type
      }
    }
  }
}

我的期望是

{
  "data": {
    "getFormTemplates": [
      {
        "name": "Form 1",
        "items": [
          {
            "type": "question",
            "question": {
              "label": "Question 1",
              "type": "shortText"

          },
          {
            "type": "rawContent"
            "question": {}
          }
        ]
      }
    ]
  }
}

【问题讨论】:

  • 为什么不使用普通的 dataType 而不是新的 GrapgQLNonNull。 ex - authorId: {type: GraphQLInt}

标签: node.js graphql graphql-js


【解决方案1】:

我会设计您的“2 级”项目,以便“类型”属性对应于实际的 GraphQL 类型,实现一个通用接口。另外,一般来说,我会设计架构,使其具有指向相邻项目的实际链接,而不是它们的标识符。

因此,如果每个表单项都可能有一个关联的模板,您可以将其设为 GraphQL interface

interface FormItem {
  id: ID!
  template: FormTemplate
}

那么你可以为你的三种物品分别设置三种不同的类型

# Skipping VideoItem
type ImageItem implements FormItem {
  id: ID!
  template: FormTemplate
  src: String!
}
type QuestionItem implements FormItem {
  id: ID!
  template: FormTemplate
  questions: [FormQuestion!]!
}

您描述的其他类型是:

type FormTemplate {
  id: ID!
  author: Author!
  name: String!
  items: [FormItem!]!
}
type FormQuestion {
  id: ID!
  question: Question
  type: String!
  label: String!
}

另一个棘手的问题是,由于并非所有表单项都是问题,因此您必须特别提及您对查询中的问题感兴趣才能获得特定于问题的字段。您的查询可能看起来像

query {
  getFormTemplates {
    name
    items {
      __typename # a GraphQL builtin that gives the type of this object
      ... on Question {
        label
        type
      }
    }
  }
}

... on Question 语法是 inline fragment,您可以类似地使用它来挑选特定于其他类型表单项的字段。

【讨论】:

    【解决方案2】:

    感谢大卫的回答!

    我已经弄清楚如何使用似乎最适合此用例的内联片段和 UnionTypes 来解决我的问题。这是代码:

    const formItemObjectType = new GraphQLUnionType({
      name: 'FormItemObject',
      types: [formItemContent, formItemQuestion],
      resolveType(parent) {
        switch (parent.type) {
          case ('question'): return formItemQuestion
          default: return formItemContent
        }
      }
    })
    

    以及使用内联片段的 GraphQL 查询:

    query {
      getFormTemplates {
        name
        items {
          ...on FormItemContent {
            type,
            meta
          }
          ...on FormItemQuestion {
            type,
            meta,
            question {
               label
            }
          }
        }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-05-21
      • 2021-01-10
      • 1970-01-01
      • 2019-10-15
      • 2016-01-17
      • 1970-01-01
      • 2018-08-15
      • 2017-08-05
      相关资源
      最近更新 更多