如何管理在输出类型中可以为空的GraphQL子objectType?

时间:2019-01-29 20:46:41

标签: node.js graphql graphql-js

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

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

  • 一级1-formTemplate
  • 第2级-formItems(templateId,类型(视频,图像,问题)-与formTemplate的1-N关系)
  • 第3级-formQuestions(当且仅当formItems.type为'question'时,与formItem呈0-1关系)

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

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

我尝试查看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": {}
          }
        ]
      }
    ]
  }
}

2 个答案:

答案 0 :(得分:0)

我将设计您的“级别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,您可以类似地使用它来选择特定于其他类型表单项的字段。

答案 1 :(得分:0)

谢谢大卫的回答!

我已经弄清楚了如何使用似乎最适合此用例的内联片段和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
        }
      }
    }
  }
}
相关问题