I'm looking at graphql. Is it possible to define an object with arbitrary attributes? Let's say I have some data like:
editOptions : { boxes : 3 , size : { width: 23,height:32} , color: #434343 }, etc...}
and this is in:
{ ... , box : { editOptions : {...} }, ... }
Let's say that editOptions is never with the same structure, sometimes not be useful to have the color, just for example sakes. In mongoose one can just define the type to something like:
editOptions : {}
These editOptions are usually unique for each box. With some attributes being shared but most being unique.
So my question is, is there a way to do this? or is this bad practice and I should change my models.
Thank you.
Use GraphQLScalarType
, simply implement it like:
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 },
// ...
},
});
You have two options.
1. Interface
If the editOptions
may vary based on the type, but are consistent for that particular type, you can use an Interface (node.js example).
Let's say you have two objects, a box and a sphere. You can define an object interface that both implement:
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]
}
In your query, you'd then return an Object
, and the requested options based for each type:
query Query {
objects(filter: "...") {
... on Box {
editOptions {
boxes
size
}
}
... on Sphere {
editOptions {
spheres
}
}
}
}
In the returned JSON, boxes will have boxes
and size
fields under editOptions
, and spheres will have spheres
.
sometimes not be useful to have the color
If for some of the boxes you don't have the color, the field would simply be empty (but still exist in the schema).
2. JSON
If the editOptions
can be really variable, you can just define the field as String, and send over serialized JSON. You'll lose all the type validations but the structure can be totally arbitrary for each object. Just make sure your client understands what to do with it.
Try JSON scalar type for GraphQL.js: graphql-type-json. It works great for me.
When using the SDL with GraphQL-tools, define GraphQLJSON as the resolver for the appropriate scalar type in your schema:
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 });
You can also use this in a programmatically-constructed schema.
See for more details on this package