GraphQL Blackbox / Any Type?

Is it possible to indicate that a field in GraphQL should be a black box, similar to how Flow is of any type? I have a field in my schema that should take any arbitrary value, which can be String, Boolean, Object, Array, etc.

+17
source share
4 answers
Answer to

@mpen is great, but I chose a more compact solution:

const { GraphQLScalarType } = require('graphql')
const { Kind } = require('graphql/language')

const ObjectScalarType = new GraphQLScalarType({
  name: 'Object',
  description: 'Arbitrary object',
  parseValue: (value) => {
    return typeof value === 'object' ? value
      : typeof value === 'string' ? JSON.parse(value)
      : null
  },
  serialize: (value) => {
    return typeof value === 'object' ? value
      : typeof value === 'string' ? JSON.parse(value)
      : null
  },
  parseLiteral: (ast) => {
    switch (ast.kind) {
      case Kind.STRING: return JSON.parse(ast.value)
      case Kind.OBJECT: throw new Error(`Not sure what to do with OBJECT for ObjectScalarType`)
      default: return null
    }
  }
})

Then my resolvers look like this:

{
  Object: ObjectScalarType,
  RootQuery: ...
  RootMutation: ...
}

And mine .gqllooks like this:

scalar Object

type Foo {
  id: ID!
  values: Object!
}
+10
source

. , GraphQL, String JSON.stringify , . , , , , JSON.parse , /array/boolean/etc.

+9

. GraphQLScalarType, .

, . , .

import {GraphQLScalarType} from 'graphql';
import {Kind} from 'graphql/language';
import {log} from '../debug';
import Json5 from 'json5';

export default new GraphQLScalarType({
    name: "Object",
    description: "Represents an arbitrary object.",
    parseValue: toObject,
    serialize: toObject,
    parseLiteral(ast) {
        switch(ast.kind) {
            case Kind.STRING:
                return ast.value.charAt(0) === '{' ? Json5.parse(ast.value) : null;
            case Kind.OBJECT:
                return parseObject(ast);
        }
        return null;
    }
});

function toObject(value) {
    if(typeof value === 'object') {
        return value;
    }
    if(typeof value === 'string' && value.charAt(0) === '{') {
        return Json5.parse(value);
    }
    return null;
}

function parseObject(ast) {
    const value = Object.create(null);
    ast.fields.forEach((field) => {
        value[field.name.value] = parseAst(field.value);
    });
    return value;
}

function parseAst(ast) {
    switch (ast.kind) {
        case Kind.STRING:
        case Kind.BOOLEAN:
            return ast.value;
        case Kind.INT:
        case Kind.FLOAT:
            return parseFloat(ast.value);
        case Kind.OBJECT: 
            return parseObject(ast);
        case Kind.LIST:
            return ast.values.map(parseAst);
        default:
            return null;
    }
}
+6

JSON . , , - , graphql-type-json.

, . , :

const { GraphQLScalarType, Kind } = require('graphql')
const Anything = new GraphQLScalarType({
  name: 'Anything',
  description: 'Any value.',
  parseValue: (value) => value,
  parseLiteral,
  serialize: (value) => value,
})

function parseLiteral (ast) {
  switch (ast.kind) {
    case Kind.BOOLEAN:
    case Kind.STRING:  
      return ast.value
    case Kind.INT:
    case Kind.FLOAT:
      return Number(ast.value)
    case Kind.LIST:
      return ast.values.map(parseLiteral)
    case Kind.OBJECT:
      return ast.fields.reduce((accumulator, field) => {
        accumulator[field.name.value] = parseLiteral(field.value)
        return accumulator
      }, {})
    case Kind.NULL:
        return null
    default:
      throw new Error('Unexpected kind in parseLiteral: ${ast.kind}')
  }
}

, ( ), ( ). serialize GraphQL, , , data, . parseLiteral GraphQL, , (, "foo", 4.2 [12, 20]). parseValue GraphQL, , .

parseValue serialize . parseLiteral AST, , , .

, . , . , , , - :

if (typeof value == 'function') {
  throw new TypeError('Cannot serialize a function!')
}
return value

. vanilla GraphQL.js, , (GraphQLString, GraphQLInt ..). Apollo, . SDL:

const resolvers = {
  ...
  // The property name here must match the name you specified in the constructor
  Anything,
}

const typeDefs = '
  # NOTE: The name here must match the name you specified in the constructor
  scalar Anything

  # the rest of your schema
'
0

Source: https://habr.com/ru/post/1683367/


All Articles