0

I have a schema type like this:

type Instance {
  id: ID!
  parentSeries: ID
  tags: JSON
}

The tags field is the dynamic JSON type (https://github.com/taion/graphql-type-json). It's also incredibly large. Ideally on the client, I can specify which fields from with tags I return. Is this possible with GraphQL/Apollo? What would you suggest if not?

2 Answers 2

1

You could include a path argument on the field and then use something like lodash's get to transform the JSON item according to the provided path:

const resolvers = {
  Instance: {
    tags: (instance, args) => {
      return _.get(instance.tags, args.path)
    },
  },
}

You could apply any number of arbitrary transformations this way to customize the returned JSON object. But, since you're returning a scalar, there is no way to just provide a selection set for the field.

Folks often feel they need to use a JSON scalar simply because the data they are working with is a map. However, a map can easily be transformed into an array, which can easily be represented in your schema without a JSON scalar. So you can just turn this:

{
  "foo": {
    "propA": "A",
    "propA": "B"
  },
  "bar": {
    "propA": "A"
    "propA": "B"
  }
}

into this:

[
  {
    "tagName": "foo",
    "propA": "A",
    "propA": "B"
  },
  {
    "tagName": "bar",
    "propA": "A",
    "propA": "B"
  }
]
Sign up to request clarification or add additional context in comments.

4 Comments

The path argument would be a string "getter" in a sense yeah? Is there anyway to get the native graphql query syntax? The transformation into an array is an interesting idea. That simplifies my schema as you say (I can do away with the json type). But what would that buy me on the query end?
WRT "native graphQL syntax", like I said, because you're using a scalar, there's no way to provide a subselection (i.e. one or more child fields) for the field. Regardless of how a scalar is serialized by the backend, by definition it cannot have child fields (unlike an object type, which can). Turning the data into an array means you now can provide a subselection of fields for the tags field because your type would now be a List of some object type.
If you do end up utilize a List, it's worth noting that can you can easily add a tagNames argument to filter for specific tags if that behavior is desirable.
That was going to be my next question (the filtering). Thanks Daniel, that was helpful
0

You could add parameter in your tags like path or some other kind of filters:

type Instance {
  id: ID!
  parentSeries: ID
  tags(path:String): JSON
}

then implement filter in your resolver like @Daniel Rearden's answer

HOWEVER! Why do you design it with a HUGE json???

Usually I use JSON when there is only a small amount of things and "shape" of data is can't be determined at compile time. or simply server doesn't care the contents of data, the client will do all the work.

In your case, the JSON data is really huge, then I guess breaking it to smaller types would be a better approach

1 Comment

Thanks. Unfortunately I don't necessarily control the shape of this gigantic JSON response at this point. I'd love to, but I can't at this point. Perhaps I can wrap this gigantic JSON in a wrapper type that exposes some of the fields I need, and gradually add them as they stabilize.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.