Announcing the Release of the Neo4j GraphQL Library 3.0.0



Neo4j is excited to announce the release of the Neo4j GraphQL Library 3.0.0! Initially driven by the requirement to perform some major dependency upgrades, we have taken the opportunity to work through a backlog of breaking changes to improve the experience with the library, and to perform some much needed cleanup in key areas.

Some of you may remember the 2.0.0 release and the significant migration effort that came along with that, but we hope that you’ll find this migration to be significantly lower impact. We’ve tried our best to limit migration activities to the server application, and any client-side changes either impact few users or are not immediately required.

I want to take this opportunity to thank the community for their continued support of and contributions to the library. We’re only a small team, and we just couldn’t push out new features and bug fixes at the rate that we do without you. Thank you!

Helping You Have Healthier Relationships


You’re here reading about the Neo4j GraphQL Library, so you already know that Neo4j is all about relationships. Ensuring that manipulating and querying relationships with the Neo4j GraphQL Library is a good experience is always at the forefront of our minds. 

We released 1.0.0 with basic support for relationships, albeit without relationship properties, which we added support for in 2.0.0. During the 2.x releases, we ensured that GraphQL Union and Interface types were supported as relationship types. 

In 3.0.0, we’re tidying up some of those loose ends to really polish the relationship experience. Expect to have much confidence in the integrity of your relationships, and enjoy new ways of querying them entirely! Read on below.

New requirements for relationship definitions

Starting with a small migration effort for some, from 3.0.0, if an n..m relationship is defined without both the List and its entries being marked as non-nullable, an error will be thrown.

This is the way.


On to some error cases – if we remove the outer Non-Null type modifier, it implies that the List can be Null. This will never happen, as an empty List will always be returned if there are no relationships.

While not crazy, this type definition doesn’t really make sense.


If we remove the inner Non-Null type modifier, it implies that the target node can be Null.

This would be… very strange.


This is where we enter a whole world of weird! With the Actor type being nullable, that would imply that the following “graph” would be possible.


This clearly makes very little sense, so we will throw an error for relationships defined in this way.

Relationship cardinality

I would like to start this section with a confession – in hindsight, this is an issue that should have been addressed long ago. Let’s take a look at some type definitions.



Given the example above, it had previously been the case that the nullability and 1..m cardinality of the director and assistantDirector fields was not enforced in the underlying database. This was obviously far from ideal.

However, from 3.0.0 onwards:

director will always have to be set on any Movie object, and cannot have more than more underlying relationship.

assistantDirector doesn’t have to be set, but cannot have more than one underlying relationship.

This is implemented via checks in the generated Cypher, so you can have high confidence that your database always reflects your GraphQL type definitions.

As a heads up, you might experience some error conditions if you have any extraneous relationships created in error by earlier versions of the Neo4j GraphQL Library.

Undirected relationship traversals

Let’s say you had a simple graph such as the one below:

You would hope that this would be reciprocal!



You might define a GraphQL type definition for this as the following:



This version of the library introduces a new argument directed on relationship fields, which allows relationships to be included in query results regardless of the direction. So to get all of the people in the graph and their friends, we can do:



Better yet, we can make this the default behavior so we don’t need to explicitly specify this argument on every query:



New relationship filters

Let’s explore some slightly more rich type definitions to walk through the new relationship filters that are available in the 3.0.0 release.



The following is only a snippet of the MovieWhere input type, showing the relationship filtering fields which will be produced from the above.



The first thing to note is the deprecation of actors and actors_NOT, which have been superseded by actors_SOME and actors_NONE, respectively. It would be incredibly jarring to remove these without notice, so they have been marked with the @deprecated directive.

They will be removed in the next major release. While we lament the loss of the simple actors field, its behavior was always unclear, and these new filters will allow for much more accurate querying of data. With that out of the way, let’s walk through some examples!

Perhaps you want to find a potentially amazing movie in which all of the actors are award winners:



Or maybe you’re not too fussy about that, and you just want to make sure that some of the actors are at least award nominated:



Maybe you have some really weird requirement, and you wanted to find any movies where only a single actor was born before 1970:



We might want to find all of the movies in our database that Tom Hanks didn’t act in (sorry Tom):



We hope you like these new filters and you use them to query your data in exciting new ways!

What Else You Can Expect in This Release


Query limit control

A quite frequently requested feature, you can now set the default and maximum number of entries that will ever be returned for a particular type. Let’s take a look at an example:



For the Record type:

– By default, 10 entries will be returned when queried.

– A maximum of 20 will ever be returned. If a client requests more than that, only 20 will be returned.

Automatically project fields needed for custom resolvers

We have renamed the @ignore directive to be @computed in the 3.0.0 release, as we realized that the only real use case was where people were ignoring a field for it to be resolved by a custom resolver.

Additionally, a from argument has been added to this new directive, which will automatically project field dependencies, for example:



Given a custom resolver:



You can now query just the fullName field, while previously you would have also had to select the firstNameand lastNamefields for it to resolve.



Deprecations

In the Neo4j GraphQL Library, we only promise to support the current supported database versions. As such, we have removed support for 4.1 in this release.

Additionally, the peer dependency on the graphqllibrary has been upped to ^16.0.0, so your project will need to have this installed.

A bunch of bug fixes

We’ve recently improved our approach to bug triage (which you hopefully noticed with the eight patch releases following 2.5.0!), and you’ll find a bunch of bug fixes in 3.0.0.

A Recap of Updates You Might Have Missed


We’ve been fairly quiet on the blogging front since the 2.0.0 release, our heads stuck into the codebase building great new features and fixing bugs. During the 2.x releases, we came out with a number of great features, including (headings are links to documentation):

Introspector: Generate GraphQL type definitions from existing data in a Neo4j database, which you can then modify if needed and host in a GraphQL server, such as Apollo Server.

Indexes and constraints: Unique node property constraints and full-text indexes are now supported by the Neo4j GraphQL Library. Specify them using the new @unique and @fulltext directives.

Aggregations: Supported in both the root-level Query type and for relationship fields, these allow you to perform complex aggregations over your data, including sums, averages, and finding limits.

GraphQL Interface relationship fields: These abstract types can now be used as the type of relationship fields, allowing for greater flexibility in your data.

Coming Soon


Full Relay support

There are a couple of loose ends to our implementation of the GraphQL Cursor Connections Specification, namely:

Connection fields in the root Query type, which will allow users to perform cursor-based pagination at all levels of the schema.

A node field in the root Query type, which will allow for the necessary Object Identification for a Relay server.

We’re hoping to get this work polished up and released soon.

GraphQL subscriptions

A much larger piece of work, we hope to soon implement GraphQL Subscriptions to allow for real-time updates of the data in your Neo4j database through the GraphQL Library.

Need a Hand Upgrading?


We’ve written a handy migration guide which you can find here. If you have any issues, come and join our community on Discord, and raise any potential issues you find on GitHub!