nexus-plugin-prisma
nexus-plugin-prisma copied to clipboard
Return JSON object from `t.field` resolver
Since prisma2 does not yet support JSON/B columns, I'm storing my JSON data in Posgres as a string.
This is fine, but Id like to return JSON to my consumers.
How can I change the return type of a string field to an object in my graphql schema?
The example below returns this error: "message": "String cannot represent value: {}",
I think I need to tell GraphQL that the field metadata
actually returns an object now.
t.field("metadata", {
type: "String",
resolve(root, args, ctx) {
const str = root["metadata"];
if (!str) {
return {};
}
return JSON.parse(str);
}
});
Im relatively new to GraphQL and prisma, so any help is appreciated! Thanks
Good question. It's also worth mentioning that seemingly it's faster to parse JSON. If I understood the video below correctly, it should be faster to parse the JSON as string on the client, than to parse the actual JSON.
https://www.youtube.com/watch?v=ff4fgQxPaO0
Make a new JSON scalar type if you do not have one available already. The following snippet is just a very basic snippet that will pass-through anything. I'd recommend looking at graphql-type-json for a more thorough implementation:
// jsonScalar.ts
import { GraphQLScalarType } from 'graphql'
export const JSONScalar = new GraphQLScalarType({
name: 'JSON',
serialize: (data: any) => data,
parseValue: (data: any) => data,
});
// updated example
t.field('metadata', {
type: 'JSON',
resolve(root, args, ctx) {
const str = root["metadata"];
if (!str) {
return {};
}
return JSON.parse(str);
}
})
If you end up implementing serialize
and parseValue
like graphql-type-json and if json
is a common output then I'd suggest using asNexusMethod
and the scalarType
constructor from the library.
// jsonScalar.ts
import { scalarType } from 'nexus'
export const JSONScalar = scalarType({
name: 'JSON',
asNexusMethod: 'json',
// check out graphql-type-json for inspiration on how to handle the rest of the scalar constructor
})
// updated example
t.json('metadata') // that's it! The scalar type would do all the parsing for you
Hope this helps 😄
For people using prisma can fix this by just adding a nexus-prisma type which has a field with type json in their schema and there you go you can now use json as a scalar type.
import { GraphQLJSONObject } from 'graphql-type-json'
import { scalarType } from 'nexus'
export const JSONScalar = scalarType({
name: 'JSON',
serialize: GraphQLJSONObject.serialize,
parseValue: GraphQLJSONObject.parseValue,
parseLiteral: GraphQLJSONObject.parseLiteral,
})
Can I use this as a query input argument?