Динамические (уникальные) объекты в GraphQl

Я смотрю на graphql. Можно ли определить объект с произвольными атрибутами? Скажем, у меня есть некоторые данные вроде:

editOptions : { boxes : 3 , size : { width: 23,height:32} , color: #434343 }, etc...}

и это находится в:

{ ... , box : { editOptions : {...} }, ... }

Скажем, что editOptions никогда не имеет одинаковую структуру, иногда не полезно использовать цвет, например, например. В мангусте можно просто указать тип на что-то вроде:

editOptions: {}

Эти editOptions обычно уникальны для каждого окна. С некоторыми атрибутами, которые разделяются, но большинство из них уникальны.

Итак, мой вопрос: есть ли способ сделать это? или это плохая практика, и я должен изменить свои модели.

Спасибо.

Ответ 1

Используйте GraphQLScalarType, просто реализуйте его как:

import { GraphQLScalarType } from 'graphql/type';
import { GraphQLError } from 'graphql/error';
import { Kind } from 'graphql/language';

const ObjectType = new GraphQLScalarType({
  name: 'ObjectType',
  serialize: value => value,
  parseValue: value => value,
  parseLiteral: (ast) => {
    if (ast.kind !== Kind.OBJECT) {
      throw new GraphQLError(
        `Query error: Can only parse object but got a: ${ast.kind}`, 
        [ast],
      );
    }
    return ast.value;
  },
});

const ReturnType = new GraphQLObjectType({
  name: 'ReturnType',
  fields: {
    // ...
    editOptions: { type: ObjectType },
    // ...
  },
});

Ответ 2

У вас есть два варианта.

1. Интерфейс

Если editOptions могут варьироваться в зависимости от типа, но согласованы для этого конкретного типа, вы можете использовать интерфейс (пример node.js).

Скажем, у вас есть два объекта, ящик и сфера. Вы можете определить интерфейс объекта, который реализует:

interface Object
type Box implements Object {
  editOptions: BoxOptions
}
type BoxOptions {
  boxes: Int,
  size: ...,
  color: ...
}
type Sphere implements Object {
  editOptions: SphereOptions
}
type SphereOptions {
  spheres: Int,
  ...
}
type Query {
  objects: [Object]
}

В вашем запросе вы должны вернуть Object и запрошенные параметры, основанные на каждом типе:

query Query {
  objects(filter: "...") {
    ... on Box {
      editOptions {
        boxes
        size
      }
    }
    ... on Sphere {
      editOptions {
        spheres
      }
    }
  }
}

В возвращенном JSON в блоках будут boxes и поля size в editOptions, а сферы будут иметь spheres.

иногда не полезно иметь цвет

Если для некоторых из полей у вас нет цвета, поле будет просто пустым (но все еще существует в схеме).

2. JSON

Если editOptions могут быть действительно переменными, вы можете просто определить поле как String и отправить через сериализованный JSON. Вы потеряете все проверки типов, но структура может быть абсолютно произвольной для каждого объекта. Просто убедитесь, что ваш клиент понимает, что с ним делать.

Ответ 3

Попробуйте скалярный тип JSON для GraphQL.js: graphql-type-json. Это отлично работает для меня.

При использовании SDL с инструментами GraphQL определите GraphQLJSON в качестве преобразователя для соответствующего типа скаляра в вашей схеме:

import { makeExecutableSchema } from 'graphql-tools';
import GraphQLJSON from 'graphql-type-json';

const typeDefs = '
  scalar JSON

  type MyType {
    editOptions: JSON
  }
';

const resolvers = {
  JSON: GraphQLJSON,
};

export default makeExecutableSchema({ typeDefs, resolvers });

Вы также можете использовать это в программно построенной схеме.

Подробнее об этом пакете см.