Announcing the Stable Release of the Official Neo4j GraphQL Library 1.0.0
Migrate your application from neo4j-graphql-js to @neo4j-graphql
Following on from our announcement of the beta release, we are excited to announce that the stable release of the official Neo4j GraphQL Library 1.0.0 is now available to download and use!
For those of you hearing about this library for the first time today, welcome! You can find a high-level overview of this library on our product web page.
The Neo4j GraphQL Library consists mostly of an npm package, @neo4j/graphql
, which is the successor to the Neo4j Labs project, neo4j-graphql-js.
It’s also a complete redesign and rewrite in TypeScript, for that sweet type safety that suits GraphQL and Neo4j so well.
Responsibility for the project has been shifted from Neo4j Labs to Product Engineering. With a team now dedicated to the new library on a full-time basis, expect high-quality support and continuous improvement.
Additionally, with today’s release also comes the stable version 1.0.0 of @neo4j/graphql-ogm
, an Object Graph Mapper. This is an amazing programmatic API for manipulating data in your Neo4j database, all powered by your GraphQL type definitions! While it uses @neo4j/graphql
under the hood, you don’t have to use them in conjunction.
My name is Darrell. I’m one of the software engineers working on the Neo4j GraphQL Library. I’m fortunate, not only to be working on this exciting product but also to be working with an amazing team who are passionate about bringing native graph data storage to GraphQL.
Today, I’m going to take this opportunity to walk you through a few of the common steps that will be required to migrate an application over to use the new library. Even if you’re not migrating an existing project, do read on to hear about some of the powerful features in today’s release, as well as some of the exciting ideas that we have for the future… 🚀
This blog contains a mixture of code examples from both the new and old libraries, separated under subheadings. If you see a 🚀in a subheading, go ahead and use any of the code there in your
@neo4j/graphql
application. See a ⚠️? Code in there is forneo4j-graphql-js
, which will soon be deprecated!
Migrating to the Neo4j GraphQL Library
The Neo4j GraphQL Library was never intended to be a drop-in replacement for its predecessor. However, the migration process isn’t too complicated. I’m going to take you through the steps of migrating a small but non-trivial GraphQL API through this process.
If you follow Neo4j at all, you’ll know that we love movies! So we’re going to take an example graph that looks like the following:
Out with the Old… ⚠️
The code snippets in this section are for the legacy
neo4j-graphql-js
library! If you just want to read about the new library, skip ahead to the next section.
Based on the graph above, a simple implementation using the old library might have looked something like the following:
Points to note in those type definitions are:
@relation
directives connecting all of our data together- An
averageRating
field to using a@cypher
directive to aggregate an average rating for eachMovie
- The unique ID field for the
Review
type, decorated with the@id
directive
Finally, you would have made a schema and hosted it using Apollo Server, as per the following code block:
To add a user, movie, and review to the database we have to run a few mutations! Make sure you keep track of the id
field of the review so that we can use it to connect our data together next.
With that ID value in hand, we can use it in our next mutations to connect everything together:
In with the New! 🚀
We need to start by switching over our npm packages from neo4j-graphql-js
to @neo4j/graphql
using npm or the package manager of your choice:
You’ll note that we’re having to install graphql
and neo4j-driver
— these are now peer dependencies in the new library, so these need to be installed explicitly.
You’ll be pleased to know that migrating the basic application above is going to be remarkably simple. The most common change is that you will need to rename all of your @relation
directives to @relationship
, and change the name
argument of that directive to be type
instead.
The @cypher
and @id
directives which we have used can remain unchanged.
Your type definitions should now look like the following:
Then you just need to make a few code changes to create a schema with the new library and host it:
- Change over your require statement (line 2 below)
- Swap out the old function for making the schema for the new constructor (line 7 below — you’ll notice I’ve passed in the driver here instead of in the context: the driver will be available in the context whichever method you use, so take your pick!)
- When constructing your Apollo Server instance, make sure you pull the schema out of the constructed
Neo4jGraphQL
instance!
With these changes made, standing up your server will look like the following:
Then for the best part. Let’s say I wanted to write another review for a different movie using the nested mutations feature of the new library:
In one mutation, I’m able to create a new movie with a new review connected to it, which in itself is connected to an existing user, before returning all of that nice connected data (but returning no nodes twice by using that filter in the selection set) in one object. Powerful stuff!
Nested mutations are a brand new feature, so you might want to migrate the syntax of your mutations first, before considering how you could combine certain mutations later down the line.
We envision that client changes are going to form the bulk of migration work, as the structure of queries and mutations has changed a lot:
- All query and mutation fields are now in camelCase instead of PascalCase, and are also pluralized —
CreateMovie
has becomecreateMovies
. - Query and mutation arguments, which were previously at the root, are now nested under commonly named arguments —
CreateMovie(title: String!)
has becomecreateMovies(input: [MovieCreateInput!]!)
. - Mutation responses now have an additional level until you reach the fields of the mutated node.
- Specifically relating to the
DateTime
scalar (as is used in this example), these are now purely dealt with as ISO 8601 strings, so you no longer need to use arguments such asformatted
.
You can check out this commit in our repository to see the inline difference, and run the above Nested Mutation if you like!
But Wait, There’s More!
In my opinion, the example above is a little too simple:
- Any user can author a review under the guise of another user, or edit other users’ reviews
- The
createdAt
field needs to be manually set when authoring a review
We should really build on our schema and add the functionality needed to address these shortfalls.
Rolling Your Own Solution Using neo4j-graphql-js ⚠️
The code snippets in this section are for the legacy
neo4j-graphql-js
library! If you just want to read about the new library, skip ahead to the next section.
I’m not going to go into the detail of implementing an auth solution in this blog. However, using the old library, we would have likely overridden the generated CreateReview
mutation with either a custom resolver or a pretty complex @cypher
directive using the cypherParams
feature (you can do pretty similar thing in the new library, too!).
Whichever method we chose, it would have needed to create a review with createdAt
set to the current timestamp, and then connect it to the currently logged-in user, and also to the movie that it addresses.
We would have had added the following mutation type to our type definitions:
Using the @isAuthenticated
directive, we would have also needed to pass a config
object to makeAugmentedSchema
specifying which auth directives we want to use:
Using GraphQL Directives for Fun and Profit 🚀
Using the new Neo4j GraphQL Library, I’m happy to say that we offer a number of directives that can essentially remove the need for a custom CreateReview
mutation entirely:
The directives to note from the code block above are:
- The
@timestamp
directive which can be used to automatically set timestamps on create and/or update operations - The use of the
@auth
directive, which in this example is being used to restrict users from creating reviews under the guise of another author, or updating other users’ reviews
This won’t automatically connect your nodes together for you, but it will protect from nefarious users taking credit for reviews that aren’t theirs!
It’s worth noting that you’ll need a method for creating users and dishing out their JWTs, such as a
signUp
mutation. Using the OGM is a really nice way to achieve this, which I won’t detail in this blog, but you can expect plenty of news in the coming weeks and months.
There’s also less boilerplate when it comes to creating your schema and server — you just need to pass your request into your context object:
Need a Hand?
We realize that hypothetical example applications are very different from the real thing, so we (and the growing community) are on hand to help you figure things out as you migrate.
This blog is by no means comprehensive, so we have written a migration guide which has a bit more fine-grained detail of schema, query, and mutation differences. This will be an evolving document that will grow and change as we continue development on the new library.
If you believe we’ve missed some functionality that should be there or something isn’t working quite as you’d expect it to, please raise an issue in our GitHub repository.
If you want to ask us or the community for a hand (or generally want to chat Neo4j and GraphQL!), please join the Neo4j Discord server where you can find a #graphql channel and a variety of other great topics to discuss.
You can also check out the GraphQL and GRANDstack category in the Neo4j Online Community.
Where Do We Go from Here?
Don’t worry, this certainly isn’t the end of development for the Neo4j GraphQL Library. Below you can find just a small insight into some of the ideas that the team has for future functionality.
Relay Implementation
If you have used them in your current neo4j-graphql-js
applications, you have likely noticed the absence of relationship properties in this release. While we realize this prevents immediate migration for a number of users, we’re aiming for this to be one of the first major features we look at after today’s release.
After plenty of discussions, we believe that implementing the Relay specification is going to provide the perfect framework for introducing relationship properties. Additionally, it will allow us to add in the much-requested feature of cursor-based pagination to help you build applications with infinite scrolling.
Aggregations
We’re pleased with the comprehensiveness of the current filters offered by the Neo4j GraphQL Library, but we want to expand these further with aggregations, allowing you to query averages, sums, and more.
Have Amazing Ideas for Neo4j and GraphQL?
On Global Graph Celebration Day, Neo4j announced the Leonhard Euler Idea Contest. This is a hackathon running from April 27 until June 4, and we want to see you turn your innovative ideas into reality using our new GraphQL library!
Not only is this an amazing opportunity to get hands on with the new library, there are also $10,000 worth of prizes available and an opportunity to gain access to Aura Free Tier for early registrants! Registration is now open.