jsonspringjava-8graphqlgraphql-schema

Filter schema-less json object in GraphQL


I have a data JSON object which has several dynamic fields, because of which I cannot define the schema in Graphql instead I defined it as Json using scalar. My requirement is to filter the fields with the data json object. One sample use case is shown below

query.graphqls

scalar Locale
scalar JSON

type Query {
    details: Details!
}

type Details {
    locale: Locale!
    name: String!
    data: JSON!
}

Details.java

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Details {
    private Locale locale;
    private String name;
    private List<?> data;
}

ScalarTypeConfig.java

@Configuration
public class ScalarTypeConfig {

    @Bean
    public GraphQLScalarType locale() {
        return ExtendedScalars.Locale;
    }
    
    @Bean
    public GraphQLScalarType json() {
        return ExtendedScalars.Json;
    }
}

SampleController.java

@Component
public class SampleController implements GraphQLQueryResolver {
public Details getDetails() {
        Details details = new Details();
        details.setLocale(Locale.ENGLISH);
        details.setName("Manu");
        List<Map<String, Integer>> allContents = new ArrayList<>();
        Map<String, Integer> contents = new HashMap<>();
        contents.put("amount", 112);
        contents.put("totalPrice", 333);
        allContents.add(contents);
        contents = new HashMap<>();
        contents.put("amount", 222);
        contents.put("totalPrice", 444);
        allContents.add(contents);

        details.setData(allContents);
        return details;
    }
}

Now when I pass the below query I'm get the output

{
  details {
    name
    locale
    data
  }
}

Output

{
  "data": {
    "details": {
      "name": "Manu",
      "locale": "en",
      "data": [
        {
          "amount": 112,
          "totalPrice": 333
        },
        {
          "amount": 222,
          "totalPrice": 444
        }
      ]
    }
  }
}

Required Usecase

But my requirement is to dynamic get only the specified fields from the data object. For example

{
  details {
    name
    locale
    data {
      amount
  }
}

should return the results like as shown below with only the amount details and not showing totalPrice

EXPECTED OUTPUT

{
  "data": {
    "details": {
      "name": "Manu",
      "locale": "en",
      "data": [
        {
          "amount": 112
        },
        {
          "amount": 222
        }
      ]
    }
  }
}

Can someone please tell me if there is a way to do this. Does graphQL supports this kind of use cases


Solution

  • It’s not possible to use a scalar json and to expect graphql to interpret any content of it.

    You can, however, use a clever approach by defining what fields in your data you want by other means:

    {
      details (dataFields: {
        amount: true
      }) {
        name
        locale
        data
      }
    }
    

    You should define a dataFields parameter, the type could be simply JSON and then you parse it in Java and include or not the fields based on that json.

    In any case it’s not possible to have a JSON that GraphQL can parse.

    You should consider creating a proper type for that data instead of a raw JSON if possible.