Editor’s note: This presentation was given by Darrell Warde at NODES 2021.
As a software engineer, I have been building GraphQL applications for several years and will be sharing the past, present, and future of GraphQL here at Neo4j. In addition to introducing GraphQL, I will provide some more in-depth demos to view. I will be referring to neo4j-graphql.js as the past, but really it is the foundation of everything that we’re building today. I will also talk about the Neo4j GraphQL library, which I’ll call the present. Then, I will share what is coming up for the library in the future. I’ll also be sharing some resources at the end of this blog. Let’s dive in!
What is GraphQL?
GraphQL is a language for defining and querying data. It also allows you to parse back language and produce meaningful results. Starting from the left side of the above image, take a look at Describe your data. You have a
type Project
, and inside it, there are a number of fields. GraphQL is a strongly-typed language. The name
and tagline
have a type String
, and contributors
is a list of users. That
User
will be another type
elsewhere in your schema. In the middle, you will find the GraphQL query language. Here you are querying for a project with the name “GraphQL.” What you’re doing is asking for that tagline back. When you execute that query against the schema that you defined on the left, you get back predictable results in the form of JSON objects, which you can see exactly match what you queried. You have project
, which is the name of your query
, and tagline, which is that single field that you asked for. That is exactly what you get returned.
GraphQL is super agnostic and can be used with any database, including Neo4j. Still, there were a number of pain points involved in using them together.
Pain Point #1: Boilerplate Code
In the case of Neo4j, translating that GraphQL into Cypher would mean lots of repeated boilerplate code, which slowed you down as you developed your applications because you had to keep writing the same code over and over again. You had to write what is known as resolvers in order to translate that GraphQL into whatever you were doing on the backend.
Pain Point #2: Developer Productivity
Since you were spending a lot of time writing boilerplate code rather than introducing valuable features into whatever you’re building, developer productivity wasn’t great.
Pain Point #3: Extensibility
It was also very difficult to extend a GraphQL API to use Neo4j in the past.
Pain Point #4: Performance
Performance was often not great with GraphQL because you often suffer what is known as the N + 1 problem, which means as you go down your tree in your graph, you essentially add more and more queries.You could be executing ten queries against the database to fetch a single set of data rather than one.
Neo4j and GraphQL
Neo4j started looking at a GraphQL API solution, which you can see in this diagram below, would sit in the middle of the GraphQL client and the Neo4j database.
The Past: neo4j-graphql.js
Neo4j-graphql.js was a Neo4j Labs product. It was essentially an experiment to validate that GraphQL and Neo4j could work together. The engineering effort was on a best endeavors basis and there was never really a guarantee of new features and bug fixes. If the team was busy elsewhere, sometimes that library might not get any updates for a while. Support was always through ad-hoc communication channels.
There was no official support for it, even if you were using it in a production application. Compare that to a product engineering product, which essentially is stable, robust, and performant with a dedicated engineering team and product managers for each product. There are going to be regular improvements because of that dedicated engineering effort, including updates and bug fixes. There’s now official support, in addition to ad hoc support.
CRUD API
Neo4j-graphql.js produced a CRUD API. You would give it this simple
type
definition for a Movie
. And from that single type definition, you would automatically get a Create
mutation which allowed you to create a single movie. You would get a Movie
query, which allowed you to specify a number of arguments to filter, sort, and paginate your results. You would get an Update
mutation, which allowed you to update movies, and also a Delete
mutation, which allowed you to delete a movie. As you come back to those pain points of boilerplate code and developer productivity, with this API you have automatically generated resolvers for these and a full CRUD API through a single type definition. However, there were some downsides to this. The API was not so consistent with GraphQL best practices, including the use of our input types at the top level. There were a lot of loose arguments at the top, which made it not such a great developer experience. There was only ever a singular operation and mutation: You could create a movie or update a movie, which meant it could be complex to create large subgraphs. There was also non-comprehensive authentication and authorization, which is an essential feature for production applications.
Neo4j <3 GraphQL
Here is the good news! Neo4j Labs set out to prove that Neo4j and GraphQL can work well together, and it became very clear to us that Neo4j loves GraphQL. They work excellently together as a tech stack. Additionally, the GRANDstack was born out of these experiments.
This is a really popular collection of software, which allows you to build full-stack applications using GraphQL, React, Apollo, and the Neo4j database. People often use this to prototype full-stack applications extremely quickly using a Neo4j database. The GRANDstack continues to live on despite the fact that neo4j-graphql.js does not.
The Present: The Neo4j GraphQL Library
The official Neo4j GraphQL Library has been given a complete rewrite. We took the best bits of neo4j-graphql.js and gave them a fresh lick of paint. It’s written in TypeScript to bring the type safety of GraphQL and Neo4j together. It also has a very comprehensive test suite, which aids development, improves quality, and prevents regressions. You have compatibility with Neo4j’s latest and greatest, including Aura Free, Professional, and Enterprise tiers.
What hasn’t changed is that we’re still 100% open source. You can see everything we are doing on GitHub. We accept contributions from the community, and we welcome bug reports and feature requests. We still do an exact one-to-one mapping of GraphQL to Cypher. A single GraphQL query produces a single Cypher query, which ensures excellent performance whilst working with the Neo4j database. You still get that great automatic CRUD API with resolvers automatically done for you.
I will now provide a demonstration of type definitions, batch mutations creating multiple nodes in a single mutation, custom Cypher, and nested mutations that allow you to mutate an entire graph through a single GraphQL mutation.
The Future: What’s Next?
Let’s move on to features that are still to come for the Neo4j GraphQL Library.
Future Feature: Relationship Properties
Many of our users familiar with the new library have been asking for relationship properties because these were present in neo4j-graphql.js. Below is a look at that:
These are some
type
definitions from the old library. You can see the relation is slightly different, and you don’t have type inside that directory. If you wanted to add relationship properties to this, you had to completely change your type definitions. You had to add in this new type, but also specify this from
and to
the direction of that relationship. Then you had to completely change the type in your movie and person type to this ActedIn
type, as well as removing the relation directive. It worked, but it wasn’t a great developer experience in terms of incrementally growing your application. We wanted to review this before we introduced it into the new library, and we’re pleased to say, we’ve come up with something that we feel is really effective and allows you to quickly grow your application.
All you have to do is introduce an interface that defines your relationship properties. It’s an interface because this is going to go in either direction of that relationship and going to be used in multiple places. All you do is add in the
properties
argument into the relationship
directive, which you already have in your graph.You can take a look at what we built by watching this demonstration:
Announcement
We’re extremely excited to announce that Neo4j GraphQL 2.0.0-alpha.1 is now available for you to use. You can install this using NPM install @neo4j/graphql@next as I did in the demonstration above, and the documentation is available at this link, this will also be available at the end of my slides as well. We encourage you to play with it and let us know how it’s working for you. It is an alpha, so we are still adding a couple of features and there will be plenty of bug fixes before we do a stable release.
Future Feature: Cursor Based Pagination This whole connection specification that we’ve introduced is actually there for cursor based pagination.
Now we have these relationship properties, this connection type with
edges
, and the movie has the actorsConnection
, which has a couple of arguments on it. All we need to do now is grow out a schema, and we can begin thinking about introducing cursor based pagination with no breaking changes to the schema to get it in. We could add in a couple of pagination arguments in first
and after
, and then a pageInfo
object, which describes if there are any pages left for you to go through. I’ll describe what a query for this might look like. Perhaps I want to get the movies where the title is The Dark Knight. Then I want to get the first ten actors. So I would execute that, and what I’m going to get back is the edges, which are going to be those actors’ details. Then I’m going to get this
pageInfo
object, which has a hasNextPage
and also an endCursor
.
Since there is a next page, if I wanted to go and get that, I would execute essentially the same query again, but I’d parse in that cursor which we got from that previous query, which would get the next ten. Then there’s another page with another
endCursor
and we can keep on rotating about that. It’s not something that we’ve built yet, but this is exactly what it would end up looking like. We are really looking forward to being able to build that!A Quick Recap of Some Other Features We Are Excited About
Aggregations We can’t wait to introduce aggregations, which would allow you to do COUNT and SUM and MIN and MAX over your data to get more value from it without querying the exact fields.
Unions and Interfaces
Unions and interfaces are a feature that we offer, but we really want to improve the support for unions and interfaces in the library.
Indexes and Constraints
We want to add support for indexes and constraints to allow you to better manage, control and query your data.
GraphQL Subscriptions
We also want to look at GraphQL subscriptions, which would give you real time updates based on when data changed in your database. This is a part of the GraphQL spec.
Conclusion & Resources
You can get in touch with us on Discord, where we are pretty active. We get really great user feedback, which really drives the direction that we take for our development. We are on GitHub, and then there is also Discourse, which is a more formal forum for requesting help with the Neo4j GraphQL library. My example code is available on GitHub under my username @nodes2021. Our documentation is available for the stable 2.0 alpha. Please take a look and feel free to play with these resources!
Drumroll… GraphQL 3.0 Was Released March 2022
This article maps out the timeline of GraphQL up until the summer of 2021. In March 2022, Neo4j released GraphQL 3.0. The product is even more robust and easy to use. In 3.0.0, we tidied up some 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!
New features include:
- New requirements for relationship definitions
- Relationship cardinality
- Undirected relationship traversals
- New relationship filters
- Query limit control
- Automatically project fields needed for custom resolvers
- Deprecations
- A bunch of bug fixes
- Full Relay support
- GraphQL subscription
We hope you enjoyed the journey through Neo4j’s GraphQL history! Stay tuned for more features to come to help enhance your Neo4j experience.