juniper icon indicating copy to clipboard operation
juniper copied to clipboard

Native scalar support for json (w/ feature = "json")

Open kestred opened this issue 6 years ago • 9 comments
trafficstars

I would like to be able to use a serde_json::Value as an Input or Output value in the graph. This can work fine for output values, but doesn't work for Input values.

Simple-ish work arounds include newtype-ing json::Value and having it serialize as some sort of string or blob--- but that causes easily avoidable and unnecessary pain for both a Javascript Client and for the server itself (which might, for example use the same struct with both diesel and juniper).

This doesn't work (I think) because using an arbitrary JSON value as an input (or output) would require unusual handling during validation that is not described by the GraphQL spec. We could, as an extension have special handling for a serde_json::Value that does not attempt to further validate the input after identifying that the input variable / input-object field is expecting arbitrary JSON.

I believe an extension like this must be implemented within juniper itself (although if I'm wrong, I'd love to know). This should be fairly low risk to add to core, as serde_json is an incredibly widely used and well supported rust crate. Presumably it would be a off-by-default feature flag since it is an extension to the GraphQL spec.

kestred avatar Nov 23 '18 04:11 kestred

Did you see https://github.com/graphql-rust/juniper/commit/2e5df9f8a469943d694a1deb67910cbbdcd6cae4 on master?

LegNeato avatar Nov 23 '18 05:11 LegNeato

@LegNeato --- that doesn't work for actually allowing a json::Value to serialize as you'd expect (e.g. as an Object rather than a blob); so it seems, at least in part because the ScalarValue trait doesn't have a way to represent complex objects.

There are no ScalarValue::as_array or ScalarValue::as_object equivalent; ParseScalarValue can't parse from an object or array (there is no ScalarToken for arrays or objects).

Presumably an alternative to providing json_scalar as a feature would be to provide a complex_scalars feature that adds arrays and objects to the scalar parsing infrastructure. While not everyone will want raw JSON scalars, the serde_json crate is more widely depended-on than chrono, uuid, and url.

Side Note: AFAIK the problem can't be fully solved by implementing GraphQLType normally for serde_json::Value because there isn't a way to allow such a type to be used as both an input and output value.

kestred avatar Nov 25 '18 05:11 kestred

Related discussion on this issue: https://github.com/facebook/graphql/issues/101

piperRyan avatar Nov 28 '18 22:11 piperRyan

Is there a workaround for this or could someone point me in the right direction in the codebase so I could submit a PR? The only place I can see is that ScalarValue trait...

mwilliammyers avatar Feb 20 '19 06:02 mwilliammyers

I'm not sure we want to do this? I don't see a massive benefit over just creating custom scalars and de/serializing Value to a string on both ends. Sure, in the schema it will ultimately be a String once you follow the scalar type def chain and clients will have to have logic, but I am not sure this is worth deviating from the spec. The comments in the above graphql issue basically point to it not being a clear win in general.

I am sure I am missing something though...

LegNeato avatar Mar 02 '19 21:03 LegNeato

In any case, I put up a PR for the current-style integration. It still serializes and unserializes to a GraphQL String though, which from the comments above sounds like is not sufficient.

LegNeato avatar Mar 02 '19 22:03 LegNeato

I guess it doesn't conform to the spec, but in another Node.js (Apollo) server I have worked with, I used something like https://github.com/taion/graphql-type-json so that you could specify JSON a lot more ergonomically via dev tools like graphiql. It is not a huge deal though, I went ahead and made my own scalar that wraps a Value via a newtype struct.

Being able to directly use Value would be a lot better though, so thanks for the PR!

mwilliammyers avatar Mar 03 '19 01:03 mwilliammyers

@LegNeato - yes, for me the benefit would be if serialization did not serialize to string; while having a standard serialized-to-string Json is useful in terms of "batteries included" for library users, I think the benefit is to minimize complexity of deserialization/serialization in clients by having it be "full" JSON (instead of serialized json within json).

kestred avatar Mar 03 '19 02:03 kestred

Any update on this?

SamKomesarook avatar May 12 '21 06:05 SamKomesarook