Skip to main content

4 min read
Andreas Marek

Welcome to the new series "GraphQL deep dive" where we will explore advanced or unknown GraphQL topics. The plan is to discuss things mostly in a language and implementation neutral way, even if it is hosted on graphql-java.com.

Merged Fields

First thing we are looking at is "merged fields".

GraphQL allows for a field to be declared multiple times in a query as long as it can be merged.

Valid GraphQL queries are:

{
foo
foo
}
{
foo(id: "123")
foo(id: "123")
foo(id: "123")
}
{
foo(id: "123") {
id
}
foo(id: "123") {
name
}
foo(id: "123") {
id
name
}
}

Each of these queries will result in a result with just one "foo" key, not two or three.

Invalid Queries are:

{
foo
foo(id: "123")
}
{
foo(id: "123")
foo(id: "456", id2: "123")
}
{
foo(id: "123")
foo: foo2
}

The reason why they are not valid, is because the fields are different: in the first two examples the arguments differ and the third query actually has two different fields under the same key.

Motivation

The examples so far don't seem really useful, but it all makes sense when you add fragments:

{
...myFragment1
...myFragment2
}

fragment myFragment1 on Query {
foo(id: "123") {
name
}
}
fragment myFragment2 on Query {
foo(id: "123") {
url
}
}

Fragments are designed to be written by different parties (for example different components in a UI) which should not know anything about each other. Requiring that every field can only be declared once would make this objective unfeasible.

But by allowing fields merging, as long as the fields are the same, allows fragments to be authored in an independent way from each other.

Rules when fields can be merged

The specific details when fields can be merged are written down in Field Selection Merging in the spec.

The rules are what you would expect in general and they basically say that fields must be the same. The following examples are taken from the spec and they are all valid:

fragment mergeIdenticalFields on Dog {
name
name
}
fragment mergeIdenticalAliasesAndFields on Dog {
otherName: name
otherName: name
}
fragment mergeIdenticalFieldsWithIdenticalArgs on Dog {
doesKnowCommand(dogCommand: SIT)
doesKnowCommand(dogCommand: SIT)
}
fragment mergeIdenticalFieldsWithIdenticalValues on Dog {
doesKnowCommand(dogCommand: $dogCommand)
doesKnowCommand(dogCommand: $dogCommand)
}

The most complex case happens when you have fields in fragments on different types:

fragment safeDifferingFields on Pet {
... on Dog {
volume: barkVolume
}
... on Cat {
volume: meowVolume
}
}

This is normally invalid because volume is an alias for two different fields barkVolume and meowVolume but because only one of the some are actually resolved and they both return a value of the same type (we assume here that barkVolume and meowVolume are both of the same type) it is valid.

fragment safeDifferingArgs on Pet {
... on Dog {
doesKnowCommand(dogCommand: SIT)
}
... on Cat {
doesKnowCommand(catCommand: JUMP)
}
}

This is again a valid case because even if the first doesKnowCommand has a different argument than the second doesKnowCommand only one of them is actually resolved.

In the next example someValue has different types (we assume that nickname is a String and meowVolume is a Int) and therefore the query is not valid:

fragment conflictingDifferingResponses on Pet {
... on Dog {
someValue: nickname
}
... on Cat {
someValue: meowVolume
}
}

Sub selections and directives

One thing to keep in my mind is that the sub selections of fields are merged together. For example here foo is resolved once and than id and name is resolved.

{
foo(id: "123") {
id
}
foo(id: "123") {
name
}
}

This query is the same as:

{
foo(id: "123") {
id
name
}
}

The second thing to keep in mind is that different directives can be on each field:

{
foo(id: "123") @myDirective {
id
}
foo(id: "123") @myOtherDirective {
name
}
}

So if you want to know all directives for the current field you are resolving you actually need to look at all of the merged fields from the query.

Merged fields in graphql-js and GraphQL Java

In graphql-js merged fields are relevant when you implement a resolver and you need access to the specific ast field of the query. The info objects has a property fieldNodes which gives you access to all ast fields which are merged together.

In GraphQL Java depending on the version you are running you have List<Field> getFields() in the DataFetcherEnvironment or for GraphQL Java newer than 12.0 you have also MergedField getMergedField() which is the recommend way to access all merged fields.

One min read
Andreas Marek
caution

Spring for GraphQL is the official and current Spring integration. The integration is a collaboration between the Spring and GraphQL Java teams, and is maintained by the Spring team.

We recommend using Spring for GraphQL, rather than the older Spring project mentioned in this blog post.

See our Spring for GraphQL tutorial for how to get started.

We are happy to release the first version of the GraphQL Java Spring (Boot) project.

As described before this project complements the GraphQL Java core project if you build a fully operational GraphQL server with Spring.

Currently it supports GET and POST requests and allows for some basic customization.

In future we are looking into supporting more advanced features like file upload or subscriptions.

As always contributions are more than welcome and we are hoping to grow this project together with the community: please open a new issue or leave a comment on spectrum chat about your wishes.

More details on how to use it can be found on the github page: https://github.com/graphql-java/graphql-java-spring

One min read
Brad Baker

One of the most common questions we get in GraphQL Java land is "can we have a datetime scalar".

This is not defined by the graphql specification per se so we are reluctant to add it to the core library and then have it turn up later as an officially specified type.

But it really is a badly needed type in your GraphQL arsenal and hence graphql-java-extended-scalars was born

https://github.com/graphql-java/graphql-java-extended-scalars

This will be a place where we can add non standard but useful extensions to GraphQL Java.

The major scalars we have added on day one are

  • The aforementioned DateTime scalar as well as a Date and Time scalar

  • A Object scalar or sometimes know as a JSON scalar that allows a map of values to be returned as a scalar value

  • Some numeric scalars that constrain the values allowed such as PositiveInt

  • A Regex scalar that allows a string to fit a regular expression

  • A Url scalar that produces java.net.URL objects at runtime

  • And finally an aliasing technique that allows you to create more meaningfully named scalar values

    We hope you find them useful.

Cheers,

Brad

2 min read
Andreas Marek

There seems to be a common misconception about GraphQL Java: that you should not use it directly, but rather use another library build on top of it.

We think it is important to make it clear, that this is not the case: GraphQL Java aims to be a library used directly without any additionally abstraction on top. It was always build with this goal in mind.

To be fair: we didn't do a very good job so far to make that clear. For example up until recently we hosted several other projects which provided abstractions on top of GraphQL Java. This was because of historical reasons and we didn't give any guidance on when to use what. There are also currently more tutorials out there which don't use GraphQL Java directly compared to tutorials which do.

The other reason people might think that GraphQL Java is not suitable is because the core project doesn't provide any easy way to get a full service with HTTP endpoint up and running. And the existing third party projects providing for example Spring Boot support are adding abstractions.

The core project doesn't deal with any form of HTTP or JSON specific things and has on purpose basically no dependencies at all. This will not change, but we recognize the need for having an easy way to get a full service up and running. This is why we are currently working on first class Spring (Boot) support.

info

Update: You can now use Spring for GraphQL, the official GraphQL integration. It's a collaboration between the Spring and GraphQL Java teams. See our quick start tutorial.

This is not done yet, but it will provide an easy way to integrate GraphQL Java in a Spring (Boot) application without adding any abstraction on top of GraphQL Java. It will also be extended over time with more advanced features like Apollo Defer support.

To recap:

  1. GraphQL Java aims to be a first class library used directly
  2. The GraphQL Java core project doesn't deal with HTTP/JSON and will continue not do it
  3. The GraphQL Java Spring project will complement the core project in providing comprehensive Spring (Boot) support

Cheers,

Andi

3 min read
Andreas Marek

We are releasing new major versions of GraphQL Java roughly every 2 months. They are major versions because we break the API in it. We do it regularly and we prioritize clean code including good naming and design very high. Actually higher than API stability.

We do that because we are optimizing for long-term growth: GraphQL Java is 3 1/2 years old and it is just getting started. This means more people will be positively affected from a better experience compared to the ones who need to refactor.

We do it also because of resource constraints: we are an open source private run project with limited time and resources. We can鈥檛 afford maintaining a badly designed project in the long-term. Every bad design, every bad naming makes adding features and adopting to new requirements harder, more time consuming and more unlikely. We also want to make external contributions as easy as possible because we can鈥檛 do it all ourself.

The last reason is personal and it is about fun. I don鈥檛 wanna maintain a badly designed project. I need to have fun if I wanna continue to invest a large amount of private time in GraphQL Java.

Does that mean we just refactor as crazy and break everything all the time? No it doesn鈥檛. We follow some rules about breaking changes:

  • We never take a functionality away. We deprecate things and make it clear that we don鈥檛 really support them anymore, but we don鈥檛 take them away without a clear alternative.

  • We try to favor simple breaking changes the compiler will catch. For example renaming a method is such a simple change.

  • We try to document in our release notes every breaking change clearly.

  • Even if we prioritize clean design higher than API stability in general we always weigh the benefits of the change vs the cost of adapting to it. There is no hard rule to that, but we always ask: is it worth it?

But we understand that not every Organization allows for regular updating major versions of GraphQL Java. This is why we started to maintain a Long-term support (LTS) version of GraphQL Java: 9.x. We will continue to back port all bug fixes to 9.x for some time and we will announce when we will switch to a new LTS version.

It is not clear yet how long this time span will be and it depends also on your feedback. Please contribute to this spectrum thread and let us know what suits you best. If you have special needs and you don鈥檛 wanna discuss it in public you can also reach us via contact form.

Cheers,

Andi