Как управлять дочерним объектным типом GraphQL, который может быть обнуляем в типе вывода? - PullRequest
0 голосов
/ 29 января 2019

Я настраиваю API-интерфейс GraphQL для nodeJS и экспериментирую с точкой блокировки для одного из типов вывода моего ресурса.

Функция представляет собой форму, которая содержит три различных уровня:

  • Уровень 1 - formTemplate
  • Уровень 2 - formItems (templateId, тип (видео, изображение, вопрос) - 1-N отношение с formTemplate)
  • Уровень 3 - formQuestions (0-1 связь с formItem тогда и только тогда, когда formItems.type равен 'question')

Мой ресурс 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": {}
          }
        ]
      }
    ]
  }
}

Ответы [ 2 ]

0 голосов
/ 30 января 2019

Спасибо, Дэвид, за ваш ответ!

Я понял, как решить мою проблему, используя встроенные фрагменты и 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
        }
      }
    }
  }
}
0 голосов
/ 30 января 2019

Я бы спроектировал ваши элементы "уровня 2" так, чтобы свойство "type" соответствовало фактическим типам 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 представляет собой встроенный фрагмент , и вы можете аналогичным образом использовать его для выбора полей, характерных для других типов элементов формы.

...