Building GraphQL APIs With The Neo4j GraphQL Library & Neo4j AuraDB

Rate this content
Bookmark

Learn how to use the Neo4j GraphQL library to build Node.js GraphQL APIs backed by the Neo4j graph database. This course covers building GraphQL APIs using the Neo4j GraphQL Library and the Neo4j AuraDB cloud-native database to build an e-comerce GraphQL API backed by a native graph database in the cloud.


Table of contents:

- Introduction To GraphQL & Neo4j

- The Neo4j GraphQL Library: modeling a graph with GraphQL type definitions; creating and querying a GraphQL API using the Neo4j GraphQL Library

- Adding Custom Logic With Cypher And Custom Resolvers: using the @cypher GraphQL schema directive; adding custom resolver functions with the Neo4j GraphQL Library

- Authorization With The Neo4j GraphQL Library: working with JSON Web Tokens (JWTs) to authenticate your API users; using the @auth GraphQL schema directive to attach authorization rules to your GraphQL API


Prerequisites:

No local setup is required for the workshop. We will make use of Codesandbox (a browser-based tool for editing and running code in the browser) and Neo4j AuraDB, a free managed database service. Some familiarity with GraphQL and JavaScript is helpful, however not strictly required. No experience with Neo4j is necessary.

146 min
06 Dec, 2022

Comments

Sign in or register to post your comment.

Video Summary and Transcription

Today's workshop focused on Neo4j and GraphQL, covering topics such as graph pattern matching in Cypher, use cases for graphs in Neo4j, and the basics of GraphQL. The workshop also explored resolver functions and performance optimization in GraphQL, as well as writing queries and setting up a Neo4j Aura database. The Neo4j GraphQL library was introduced, highlighting its features and the ability to add custom logic and authorization. The workshop concluded with a discussion on connecting Neo4j Aura to a Node.js GraphQL server and implementing custom resolvers and authorization rules.

Available in Español

1. Introduction to Neo4j and GraphQL

Short description:

I work for Neo4j, an open-source graph database company. Today, we'll focus on the back-end piece of a full stack application, working with the database, building a GraphQL server, and using cloud services. We'll use Neo4j Aura as our database and the Neo4j GraphQL library to build GraphQL APIs backed by Neo4j. We'll also explore adding custom logic and authorization to our GraphQL API. No need to set up a local development environment; we'll use hosted services like Neo4j Aura and the Neo4j GraphQL Sandbox.

So just a little bit about me. My name's Will. I work for a database company called Neo4j. Neo4j is an open-source graph database. We'll talk about what that means and we'll do some hands-on exercises with Neo4j as we our GraphQL API. So I work on the developer relations team at Neo4j, and so roughly that means helping people build applications with graphs and Neo4j. I also work on integration tooling, so making sure that you can use Neo4j with different tools in the ecosystem. GraphQL is one of those. I also recently wrote a book published by Manning called Full Stack GraphQL Applications, which you can actually download for free. This link dev.neo4j.com slash GraphQL dash book.

What we're going to talk about today is largely the back-end piece of a full stack application, right? So we're going to work with the database. We're going to build a GraphQL server, and we'll use some cloud services to host that in the cloud. But we're not going to talk about how do we integrate GraphQL into our front-end application. The book goes into a lot more detail on that.

So the rough outline for today. We have a few different modules to work through so I'll have a mix of some slides and examples. And then we have at least one or two hands-on exercises for each one of these modules that we're going to go through. So we're going to start off with what I think for some folks will be a recap of an intro to GraphQL but just make sure that we're all roughly on the same page. Starting out here. Then we'll take a look at Neo4j. We're going to use a hosted database as a service called Neo4j Aura. There's a free tier. We can just click a couple buttons and spin one up. So that's going to be our database for today. And then we're going to look at using the Neo4j GraphQL library which is a database integration for GraphQL and Neo4j that makes it easier to build GraphQL APIs backed by Neo4j. So we'll look at a couple of different ways to get started using the Neo4j GraphQL library. We'll look at how we can add custom logic to our GraphQL API using the Cypher query language. Cypher is the database query language that we use with Neo4j. But there's a very interesting way that we can combine that with GraphQL to add custom logic. And then if we have time, which I'm not sure if we'll get to this but we'll at least talk about this, is how do we add authorization to our GraphQL API using some of the features in the grew up to library to define authorization rules in the GraphQL schema and JSON web tokens.

So you don't need to worry about setting up a local development environment or cloning a GitHub repo or anything like that. We're just going to use posted services. So I mentioned we're using Neo4j or a DB, the free tier of that. We're going to use a tool called the Neo4j GraphQL Sandbox, which is a sort of in browser tool for working with GraphQL and Neo4j. And then we're going to use code sandbox to run some JavaScript code. So we do have a bunch of links to slides here and various resources, documentations. But I'll talk about these as we go through them. Cool.

So let's talk a little bit about Neo4j. I think some folks said they're not familiar with Neo4j. So Neo4j is a graph database. So unlike other databases that use tables or documents as the data model, Neo4j and other graph databases use what's called the property graph data model. So a graph, entities, those are nodes and relationships that connect nodes. That's the basic data model that we work with in a graph database like Neo4j. We use the Cypher query language primarily to work with Neo4j. There are other ways of interacting with the database, which we'll see today. Primarily, you can think of Cypher as kind of like SQL, but for graphs. There's an example here in the, kind of the upper right, talking about addresses. Something in New York, registered address, connected to officers and entities. And there's this sort of ASCII art graph pattern drawn here.

2. Introduction to Cypher and GraphQL

Short description:

Graph pattern matching is a core part of Cypher. Patterns in Cypher are defined using an ASCII art representation. We use parentheses to indicate nodes, arrows to represent relationships, and shorthand notation for outgoing relationships. An example query from the Panama Papers Dataset is used to illustrate the use of Cypher in graph analysis. We will discuss Cypher further after exploring GraphQL.

So what is this about? Well, graph pattern matching is kind of a core part of Cypher. So the way that we define patterns in Cypher is to use this ASCII art representation. So the parentheses, first around address, that's indicating a node, so we're looking for address nodes where the address contains New York. So find addresses in New York, and then this arrow that we've drawn here with the registered address, that's representing a relationship connected to officer nodes. And then we have the shorthand for an outgoing relationship now to these entity nodes. So this is saying, find addresses in New York, find officer nodes connected to those addresses through this registered address relationship. And then find any entities connected to those officers with an address in New York. I have used this query as an example, because this comes from the Panama Papers Dataset, which was a data journalism investigation a few years ago, where the data journalists at the ICIJ, used Neo4j to make sense of these leaked documents about offshore companies, because that was a very graphy problem with, sort of, nested structures of offshore companies and things like that. So we'll talk a bit more about Cypher after we sort of, dig into GraphQL a bit.

3. Graphs in Neo4j: Use Cases and Ecosystem

Short description:

There's a spectrum for use cases for graphs in Neo4j, ranging from application development to analytics. Depending on the use case, the tools in the ecosystem may vary, such as visualization tooling for analytics and data science or building APIs for transactional use cases. A database is core to infrastructure, requiring the ability to work with data in various tools.

On this slide, it is really showing that there's a spectrum for use cases for graphs in Neo4j. I'd like to just show that there's a large ecosystem of tooling, right? So as a database, we sit in the middle of infrastructure and architecture for lots of different use cases and users, and there's the spectrum on the left for sort of application development to analytics on the right. So things like graph data science, graph algorithms, these sorts of things. And depending on where we are in that spectrum, what you're trying to accomplish, what your use cases are, the tools in the ecosystem that you're integrating with are a bit different. So for things like analytics and data science, we may be more interested in integrating with some visualization tooling, some machine learning pipelines, things like that. On the left end of the spectrum where we're talking about application developments, building APIs for transactional use cases, these sorts of things, that's more where we are today talking about building a GraphQL API for our databases. But there's lots of tooling in the ecosystem because a database is so core to your infrastructure you need to be able to work with data in lots of different tools.

4. Introduction to GraphQL

Short description:

Let's talk about GraphQL, a query language for APIs. It uses a strict type system to define data and allows referencing other types on fields. The client asks for specific data, and the response matches the query shape. We typically use the Schema Definition Language (STL) to define types, and we can use schema directives for custom logic.

Cool, so let's talk about GraphQL. I think most folks, it sounds like have some level of familiarity with GraphQL, maybe just on the client side, maybe just the server side, so let's talk about some GraphQL concepts and then we'll take a look at a running GraphQL API to write some GraphQL queries.

So first of all, what is GraphQL? GraphQL is an API query language. We use a strict type system to define the data that we're working with in GraphQL. They're called type definitions. Those type definitions define the data we're working with, how those types are connected, and that's where the graph part of GraphQL comes in, right? We can reference other types on fields. At query time, the client asks for exactly the data needed for building an application to render that view, whatever that may be, and then the response, matches the shape of the query, so we know exactly what data we're getting back from the API.

So in our type definitions, we typically use the Schema Definition Language, or STL to define our types. Of course, we can define types programmatically. STL is nice because it's language agnostic. I can use STL if I'm building my GraphQL API in JavaScript, Python, Go. There's a few interesting concepts in the type definitions. So first of all, we define types. Types have fields that have a type as well, right? So here we have movie, genre, and actor are our GraphQL object types. And movie has things like the title, but the string, years, and integer, so on. And then here we have a relationship field, genres, that is connecting the movie type to the genre type. And we'll see in a minute, when we start working with the Neo4j GraphQL library, that we can annotate these type definitions using what are called GraphQL schema directives. And schema directives are GraphQL's built-in extension mechanism that allow us to say, hey, some custom logic should occur here. And we'll see what that is and why we use that in a minute.

5. GraphQL Operations and Selection Sets

Short description:

So that's type definitions. Let's talk about GraphQL operations or commonly called queries. So here's a GraphQL query. The entry points, which in this example is the movies entry point that maps to a movies field on the query type. And we can pass arguments there. And the rest of our GraphQL operation is a nested object called the selection set. The selection set specifies a traversal through the data graph, expressed through nesting. The response matches the shape of our selection set.

So that's type definitions. Let's talk about GraphQL operations or commonly called queries. So operations can actually be of three different kinds, a query, a mutation, or a subscription. And these match to fields on special types, the query type, the mutation type, and the subscription type.

So here's a GraphQL query. So the entry points, which in this example is the movies entry point that maps to a movies field on the query type. And we can pass arguments there. So here we are passing a, where argument to filter for only movies with the title, A River Runs Through It. And then the rest of our GraphQL operation, there are still a GraphQL query is a nested object called the selection set. And the selection set specifies the, I guess it specifies two things really. One is it's specifying a traversal through the data graph. So we said that the graph and GraphQL are these relationship fields that are types referencing connections to other types. And that traversal in a selection set is expressed through nesting. So here, for example, we start with the movie A River Runs Through It. We then bring back the title of the movie and then we traverse to the actors and grab the name of each actor connected to this movie that we're searching for. And here, when we go to Directors, we find directors of this movie and then other movies that those directors have directed. So this is a traversal through this data graph just by sort of nesting our selection set. The response matches the shape of our selection set. So on the right there, is the JSON object that we get back from the results of this GraphQL query. We can see exactly the fields specified in our selection set are returned.

6. Resolver Functions and Performance Optimization

Short description:

Resolver functions are where the logic for resolving a GraphQL request lives. They help address performance issues like the N plus one query problem. GraphQL provides benefits such as over-fetching and under-fetching, improving developer productivity. However, challenges arise as REST concepts may not directly apply to GraphQL APIs. Introspection is a powerful feature in the GraphQL ecosystem that enables the creation of developer tooling. GraphQL Playground is a popular tool for exploring and querying GraphQL APIs. Let's explore a running GraphQL API at movies.neo4j-graphql.com using GraphQL Playground.

So that is talking about type definitions. We talked about GraphQL operations, this concept of a selection set. How do we actually define the logic for fetching data from the data layer when we're building a GraphQL API? Well, that comes in with these resolver functions. So resolver functions is where the logic for resolving a GraphQL request live. So here in this example, we have a resolver map of functions for a conference app. And so we have one entry point. So one field on the query type called session and in that resolver function, we are accessing some database ORM layer and we're searching for sessions by some search string. So imagine we have a conference application and we want to allow users to search for like GraphQL or something in the conference schedule and then see the sessions, what room they're in, similar sessions that they might be interested and so on. And we have resolvers for each of these fields.

So once we've found the sessions in the database that match our search string, well then if the user has selected it, we need to then go back to the data layer to find out what room that session is in. Need to do the same thing for the theme and then need to go back again to find any sessions that are recommended based on the session that we found searching the schedule. And this is due to the nested way that resolver functions are called, right? So resolver functions are called first starting at the root level, in this case, the session field on the query type. And then in this case, we have three sessions, three resolvers on session room theme and recommended. So if those fields are requested in the selection set, we're gonna make three more round trips to the data layer for each session that we've found. Now you can see where some performance issues might come up here. We don't wanna be making potentially expensive round trip queries to the data layer multiple times for each GraphQL request. And we certainly don't wanna do it in the case where we found a whole bunch of sessions that match our search string and then make multiple requests for each session that we found that that could potentially be really slow. So this is pointing out, what's commonly called the N plus one query problem, where we ended up making lots of requests to the data layer for any arbitrary GraphQL requests. There are a few different ways to address this. One common approach is called data layer, or sorry, data loader, which allows us to batch and cache the queries so that we're reducing the number of requests sent to the data layer, that can add some additional complexity. So another way to address this problem is to use database integrations for GraphQL that can generate a single database query from the root level resolver. And that's exactly what the Neo4j GraphQL library does. So, instead of calling multiple nested resolvers in this way when we're using the Neo4j GraphQL library, we'll actually generate a database query at the root resolver, so we don't have to worry about this N plus one query problem.

So some benefits of GraphQL, I think folks have probably seen most of these things before the most common or most commonly talked about benefit of GraphQL I think that I see is this idea of over fetching and under fetching, so being able to make just one request to the GraphQL layer, to render all the data needed in a view of an application rather than making multiple requests to the back end, and then slimming down the network response so that if I'm only showing, I don't know like in a list of blogs I'm only showing the title and author of the blog I don't need to fetch all this other metadata or even the full content of the blog post, things like this that are not being used to render data in my view. So GraphQL addresses both of those issues. There are also lots of big developer productivity boosts I think as well of GraphQL. Of course there are some challenges that come up. I think the biggest category of challenge that can come up with GraphQL is that a lot of things that are well understood from the world of REST don't necessarily apply when we're building GraphQL APIs. So things like HP status codes don't quite mean the same thing, error handling and caching can be done a bit differently. We talked about this N plus one query problem, which can be problematic if you're not anticipating that when you're getting started building your API. So there are best practices and tooling. So software libraries and packages that address all of these things, but these are some of the most common things that can come up. So one of the things that is really nice about the GraphQL ecosystem is tooling. So there's one feature of GraphQL that we haven't talked about yet that powers a lot of the cool GraphQL tooling that we see, and that is this idea of introspection. So when we have a running GraphQL API, we can send what's called an introspection query to the API. The introspection query basically says, send me all of the types that you have available in the API, send me the schema of the API. And then we can use that to build really powerful developer tooling. So things like client side syntax checking for GraphQL queries, we can have auto-complete based on the introspection and then these in-browser tools. So things like GraphQL Playground, GraphiQL or Apollo Studio. Apollo Sandbox is the part of Apollo Studio that has this sort of in-browser query functionality where we can basically view documentation of the GraphQL API generated from the introspection query and then also have these nice auto-complete syntax-checking features as we're writing GraphQL queries and working with the results. So today, we're gonna look at GraphQL Playground in a couple of different examples, but functionality is similar for using GraphQL Playground, GraphiQL or Apollo Studio similar concepts apply.

Okay, cool. So let's dive in and take a look at a running GraphQL API. So let's go to movies.neo4j-graphql.com, you will see, actually let's, maybe this is easier, maybe I can have the slides and GraphQL Playground side by side, we can keep track of what we're doing. So let's see if we can write some GraphQL queries. So we'll open up this movies.neo4j-graphql.com and we'll see, we'll probably have a blank GraphQL editor there on the left. And so this is GraphQL Playground, this is a GraphQL API that's up and running that has data about movies. And if we go to the schema tab, we can see the full schema for the API, but if we go to docs, we have a little more human readable for the data available in our API. And so, first off, we can see the query fields that are available. So things like movies, genres, we have some aggregations and connection fields as well.

7. Exploring API Schema and Writing Queries

Short description:

We have movies, users, actors, directors, and detailed information about movies. We can pass arguments for filtering and options at the query field level. Let's explore the API schema, write GraphQL queries to answer questions about movies, and then move on to the next section.

We'll talk about those later on, but we have things like movies, users, actors, directors, and if we drill down and see, we have detailed information about movies. Movies are connected to things like actors and can go from actors to other movies they've acted in and see all the fields available. Now we can also see the arguments that we can pass in for things like filtering apparently or options at the query field level.

Okay, and so our exercise here is to explore the Docs tab, learn more about the API schema. Well, we did that. And then write a few GraphQL queries to answer a few questions. So we find the title is the first 10 movies ordered by title. Who acted in the movie Jurassic Park? What are the genres of Jurassic Park? And what are other movies in those genres? So let's spend a couple of minutes seeing we write queries to answer those questions. And then we will move on to the next section where we will dive into seeing how this GraphQL API is built and take a look at Neo4j. So I'll pause for a minute or two and give folks some time to play around with this. And then we will take a look at the answers for this.

8. Writing GraphQL Queries and Setting Up Database

Short description:

To retrieve the titles of the first 10 movies ordered by title, we use the movies entry point and specify the options field argument to limit the results and sort them by title. To find the actors in the movie Jurassic Park, we use the movies entry point with the where argument to filter by title and the actors field to retrieve the names of the actors. We can also retrieve the genres of Jurassic Park and find other movies in those genres by traversing from the genres field to the movies field. To limit the number of movies in each genre, we add the limit argument at the field level in the selection set. Moving on, we will set up our database using Neo4j AuraDB, a hosted database as a service. We can sign up for the free tier, which allows us to create private databases and choose the Graph-Based Recommendations dataset to load the movie and user rating data.

Okay, did everyone get this first query, which is find the titles of the first 10 movies ordered by title? Well, we can look in the docs to see that we have the movies entry points. So we'll start there. So movies, and then we can see with the control space, the different fields available. And that's the title, we know we want that. But we know we want just the first 10. So if I look in the docs, I can see for the movies query field, there's a couple of arguments, which I need to explain more down here. So there's a where argument, which has things like filtering functionality it looks like, so that's not quite what we need in options though. We have sorting and limiting. So I think that's what we want. So let's add an options field argument here. You wanna limit, what did they say? First 10 movies. Let's test this, that gives us 10 movies, but we want these to be sorted by title. So let's add sorting, and then we need to specify a sort direction. And so in this API, we can start by title, then ascending or descending order. And if we do that in ascending order, we can see here, got some special characters that start first. So here's our first 10 movies ordered by title. Cool.

Anyone get this next question, which is, who acted in the movie, Jurassic Park? Did anyone get that one? Well, let's take a look. So we saw previously, that movies has a where argument. And if we look at the fields in that, we basically have filtering for each of the fields available on the movie type. You can see for string fields, we have these various contains, starts with, ends with, and for numeric fields, you have things like greater than, less than, and so on. And so here, let's do a title. Is Jurassic Park or this work, it's going to find us. Okay, so here's Jurassic Park, found it, but we want to know the actors. And so again, just searching for things by control space autocomplete, helps us to kind of see what's available, actors, that sounds like what we're looking for, and actors bring back the name field. So here's our actors in Jurassic Park. And then similar, what are the genres? So let's bring back the genres, Jurassic Park adventure action, sci-fi thriller. And then what other movies are in those genres. So now we can traverse from the genres to other movies, by adding this movies field. However, if I just run this, well, we have potentially, I don't know, tens of thousands of movies in the database, maybe thousands of movies in the database. So there's probably, I don't know, thousands of thrillers, thousands of sci-fi movies. So let's add a limit here. So we can also add arguments at the field level in our selection set. So let's just add a limit tens over each of these genres. Let's just bring back 10 other movies in each of those genres. Cool, did everyone get those? Is anyone stuck or confused on those? I think for those familiar with GraphQL, hopefully this was a bit of a review of the concepts, although maybe I haven't seen this specific API before. V-Sys, cut up, okay, cool, great.

Well, let's go ahead and move on then to talking about data and Neo4j. So that's writing some GraphQL queries and overview of some GraphQL concepts, so let's talk about building our own GraphQL API. But first, we're going to set up our database. And so for this, we're gonna use the Neo4j AuraDB, which is a hosted database as a service from Neo4j that gives us hosted Neo4j instances. And I'll share a link here in the chat, the dev.neufj.com slash neo4j-aura, or you can just search Neo4j Aura in Google. And so we're gonna select the free tier, we can sign up with Google, and maybe a couple of other services, or you can create a username with email and password, and then you'll be asked to choose free tier. There's a few different tiers, there's free, professional, and enterprise tier. So free tier allows us to create databases that are private to us, so we get the connection credentials private to us, but the database stays around. So this is good for hobby projects, if we want the database to stick around for a while. We can also start with loading an existing dataset, so we're going to choose the Graph-Based Recommendations dataset. That's gonna load actually the same movie and user rating data that we were just working with. So let's see what this looks like. I'm gonna go to dev.newtra.com, new from J, dash, Aura, and we'll zoom in a bit, so I'm gonna click on Start Free.

9. Creating Neo4j Aura Database

Short description:

I was already signed in with my Gmail. We want the Graph-Based Recommendations. This will load initial data into our database. I copied the password and downloaded the .env file. Let's pause for a minute for everyone to create their own Neo4j Aura database. We'll then build a GraphQL API on top of it.

And I was already signed in. I think I just signed in with my Gmail. And initially, I think you'll see this screen. If you don't, just click Create Instance, and we want the Graph-Based Recommendations. This is going to load some initial data in our database. So I'll hit Create. This is an important step, so this is the password for my database, and I can copy the password or I can download a.env file that has the connection credentials. So I'm gonna copy this and I will also download the.env file. And yes, I have copied that all good. Okay, and this will take a few minutes to spin up in the cloud. So let's pause for a minute or two because everyone will want to create your own Neo4j Aura database. We're then going to build a GraphQL API on top of your private Aura instance. So go ahead and follow these steps, be sure to save your generated password, you download the.env file, copy and paste the password somewhere because you will need that in a moment. So we'll pause for just a minute for everyone to go through this process, and then we'll take a look at the data that we just created. Let us know in the chat if you have any problems or get stuck.

10. Setting up Neo4j Aura and Exploring the Workspace

Short description:

I wouldn't recommend saving your password in the chat. Once your instance is running, you'll see a green dot indicating its status. The free tier of Aura has limitations on the number of nodes and relationships you can store. The connection URI is used to connect to the database. The Explore tab in Neo4j Bloom allows visual exploration of the graph data. You can search for movies and view their genres and details. The Query tab is used to write Cypher queries and work with the results. Cypher is based on graph pattern matching using ASCII art representation.

Bee's asking, can I save my password here in the chat? I wouldn't recommend that in the chat. So there's a way to send a chat just to yourself, maybe that makes sense. But you generally don't want other folks to see password.

Our instance is up, great. Let's take a look at what we got then. Okay, so once your instance is running, you'll see this green dot saying that, hey, this is running. So there's a few things. The free tier of Aura is limited by the number of nodes and relationships you can store in the database. So that's what these 14 and 42% things are. And then the connection URI. This is how we connect to this database from the database drivers or some of the different developer tooling. And if I click on this Open button here, that's gonna take me to Neo4j Workspace, which will ask me for my password here. That's the password for my specific instance. Now, you may see, instead of Open, you may see something that looks like this, Explore Query Import. This is the classic view, we have these, these are three different developer tools broken out individually. If you don't see where it just says Open, if you click here on your user icon, it'll tell you if you're using the classic experience or the workspace, which I guess is, I think should be, should now be the default for folks. This is a relatively new way of organizing the developer tools, it's basically combining those three query explore and imports into one tool. So I would recommend using the workspace view since that's the new on but again, I think that's the default. But anyway, you should see something kind of like this with zoom in a bit with explore query and import at the top here.

So explore, this is a visualization tool that allows us to explore the graph visually without writing any code. So I'm just gonna generate a perspective here. It's just going to inspect the data and allow us to visualize the data. The perspective is what basically allows us to map the data to the visualization. So maybe I don't want all of the data to be available in the visualization tool, that sort of thing. But what's nice about this explore tab, which this is a tool called Neo4j Bloom, if you've seen this before, says yes, so scenes is empty. Yeah, that's fine. The scene is empty is just means that we haven't returned any data yet. So let's try to search for a movie. So what's nice about this is we have this sort of natural language way of searching. So I'm gonna search for movie by title. We were looking at Jurassic Park earlier. So let's look for Jurassic Park. And you can see as I'm typing, it's giving me some options here. So let's find what are the genres of Jurassic Park? Oh, we ended up finding a couple. We have Jurassic Park and Jurassic Park. Three and you can see the genres of those. We can double-click to get details on the nodes. We can expand out to see the actors in the film and so on. So this is just a way to interact visually. This is useful for, if we're building something like a tool for an analyst who is not going to write database queries, but we want to give them a visual tool to explore our data, we can configure this visualization. We can add custom logic to it as well, sort of set it up for more of an analyst role. We're going to also use this Query tab. Let's zoom in quite a bit here, maybe not that much. So the Query tab, this is where we can write Cypher queries and then work with the results. Before we start writing some Cypher, I think I have just a couple of slides to talk a little bit about some Cypher concepts. Okay, so we did all this, this is just walking through, setting up Neo4j Aura. So we saw that example at the beginning on one of the first slides when we were looking at an example of a Cypher query looking at folks with an address in New York that were connected to offshore legal entities. And the foundation of Cypher is this idea of graph pattern matching. So here we're using the match keyword, match is saying, hey, you'll find this pattern where it exists in a graph. And we can build up these patterns using this ASCII art representation of a graph.

11. Defining Nodes and Relationships in Cypher

Short description:

The most fundamental pattern in a graph is a node, which can be defined by enclosing it in parentheses and adding a label. We can refer to parts of the pattern using variables and add predicates to filter the results. Relationships in a graph are defined using square brackets and can have a type and direction. We can search for nodes and relationships based on their labels and types. The direction and type of relationships are important when mapping the graph model to GraphQL. We can bind variables to relationships and use them in our queries. For more information, refer to the Cypher cheat sheet and the Neo4j documentation.

And so the most fundamental pattern we can define as a node, and so that's an open and a close parentheses, that's sort of drawing a circle, right, drawing a node. We can add onto that pattern by adding the label of the node. So, labels are a way to group nodes, you can think of them if you're familiar with relational databases as similar to a table from a relational database. So this is set, this pattern on the second line says find nodes with the label movie.

Once we've matched on a pattern, it's useful to then be able to refer to pieces of that pattern later on in our Cypher query. And so that's where the M here on the third line comes in before the colon. And so this is saying, bind the variable M to any pieces of the graph pattern, in this case, the node. So the movie node that I can then use to refer to this piece of the pattern later on in the query. So M is now my movie node. I can add inline predicates, or I can also use this where clause to define predicates. But for inlining property equality predicates, I do that inside curly braces. So here it's curly braces now inside the parentheses says find movies with the title, Jurassic Park. This is equivalent to match in movie where M.title equals Jurassic parks. You can see here, we're using the M variable that we bound to the movie M over here in this part of the query. So these two with the curly braces or the where clause, these are equivalents but with the where clause, we could also instead of the equality operator, we could say where M.title contains Jurassic Park or starts with Jurassic Park, things like that. And then once we've matched on a pattern, we can return it, we can return the results to see what data we've matched on. So that's nodes, but we're working with graphs. So relationships connect nodes. So how do we define relationships in the graph? Well, relationships are square brackets. So here in that first line, that's the most basic form of relationships that we can define, which is just a blank relationship. So it's basically saying match on all relationships in the graph.

We have a similar concept for relationships, similar to the labels of nodes, relationships have a type. One difference between relationship types and node labels is that we can have multiple node labels. So Rafael was asking if we're saying search all tables tag as movie? Yeah, so we are specifically searching for nodes that have the label movie. So we don't have tables in a graph database, but conceptually, we can think of the concept of labels as similar to tables. I guess, the equivalent analogy would be nodes are like a row in a table if that makes sense. But yeah, so this is basically saying, find all nodes that have the label movie. And we'll look at some examples of this in a moment. Hopefully, that will clarify a bit. And then the concept of labels for relationships with the relationship type is very similar, but we have a single relationship type. Whereas with nodes, we can have multiple node labels. And in fact, in our data set, we do, we'll see that in a minute. We have nodes that can be both movie, not in this case. We have, what, actor? We have actor and person or you can also be an actor and director in the database as well. Anyway, now, relationships also have a direction. And that's where this caret comes in to kind of draw an arrow to indicate the direction. We can treat our graph as undirected. So when we're searching for patterns, if we don't want to include direction as part of the pattern that we're searching for, we just leave that arrow off. But when that relationship is stored in the database, there is a direction. This idea of direction and relationship type, these are important, because we'll come back to these when we start working with GraphQL to see how we map this piece of the property graph model that we use in the database, how we map that to GraphQL. So as I mentioned, the relationship schema directive earlier, we're going to use that to encode the relationship type and direction. But anyway, that's getting a little bit ahead of ourselves. And so, similar, we can see how we're building up our pattern here to now search for relationship connecting an actor and a movie, we can bind variables to our relationship just like we did with nodes. So here we're using r to refer to the relationship that connects the movie Jurassic Park and any actors. And I linked here the Cypher cheat sheet, which is like a reference card for Cypher. There's lots of examples here. This is helpful for sort of seeing what's available in Cypher a lot more concise than the official documentation. Which while we're talking about documentation, let's bring up the Neo4j documentation, which I'll drop a link to in here. There's a section specific to Cypher that goes into a lot more detail than the Cypher cheat sheet, which is mostly just sort of showing syntax examples. And then the other piece of documentation that we want to just be aware of for today is the Neo4j GraphQL library here.

12. Exploring Cypher and Graph Patterns

Short description:

We discussed the basics of Cypher and explored how to use it in the Neo4j workspace. We learned how to write Cypher queries, visualize the results, and store properties on nodes and relationships. We modified our query to include the relationship piece and explored complex graph patterns using Cypher. We also discussed exercises related to finding movies in the Matrix series, actors in the Matrix movies, and average user ratings. Next, we'll explore the features of the Neo4j GraphQL library and build a GraphQL API on top of the Aura Database.

Drop a link to that. This is linked in the side, but this we're gonna start using in a moment as well.

Okay, so we talked about some basics of Cypher. Let's see how we use this. So I'm gonna go back to Neo4j workspace. So we looked at the explore tab. This is for visualizing the graph and exploring the graph visually. So the query tab, this is where we can write our Cypher queries and visualize the results. So, match m colon movie title, Jurassic Park is what we're looking for, and then we can return m. So this is what we saw on the slide a minute ago. And we get back this single node. So we get a graph view. We double click on this, we can start to explore the data a bit, but this is perhaps not as helpful as what we want because we've now also added all of these user rated. So here's a user and they rated Jurassic Park a 4.5. So we can store properties or the attributes. So that's the actual data. So things like title, we can store those on both nodes and on relationships. So here's this rated relationship that has a rating property of 4.5, that has a timestamp of when this was created. So we can store arbitrary key value pairs, we call them properties on both nodes and relationships.

Okay, let's modify our query a little bit to include the relationship piece of things. So actitive in actor, and then I need to add the direction. So note that we can write our queries, kind of either way, we just have to make sure we get the direction of our relationship, correct? So actor acted in movie. And I wanna return, let's just return star to turn everything, not just the movie node. Cool, so here we go, so here's Jurassic Park, we have the actors, and again, I can kind of double click to explore the graph. So here's Jeff Goldbloom, here's a bunch of other movies that he was in as well. But I can, rather than sort of just clicking through, I can define any movie nodes define any arbitrarily complex graph pattern here using Cypher. So if I wanted to find who acted in Jurassic Park and what other movies they acted in, I would just add on to that pattern like this. Oh, and the reason we're seeing these as disconnected because I didn't bind anything to this second acted in relationships. So I can call that R2 and that will give me Jurassic Park, the actors of Jurassic Park, and then what other movies those actors acted in. Interestingly, it doesn't look like at least these four, Jeff Goldbloom, Sam Neill, Richard Attenborough and Laura Dern were in any other movies together, at least not in this database. So I can bind pieces of the graph pattern to variables or I can just bind the entire path I think, so I could do something like this where P is this path and then I'm returning the path and then I don't have to think about binding all of these or declaring variables and cipher for all of these pieces of the pattern. So I can remove those.

Okay, let's take a couple of minutes for folks to go through the exercises here, so let's write some cipher queries to find the movie, the Matrix. Can we find other movies in the Matrix series? Who acted in the Matrix movies? What other movies were they in? What's the average user rating of each of the Matrix movies? And then this last one, this is going to be useful for when we start adding custom logic to our GraphQL API is what movies would we recommend to someone who likes the Matrix, so starting to think a bit about can we write a recommendation query. So use the cipher documentation that we saw, the cheat sheet to try to write some graph patterns to answer these questions. And we'll pause here for a few minutes to give folks some time to work through these. And then we'll come back and go through the solutions together. And then just to give you a look ahead of where we're going next, the next thing we're gonna look at is the features of the Neo4j GraphQL library. And we're now gonna start to build a GraphQL API on top of the Aura Database that we just created. So the first question is find the movie The Matrix, Rafael said he got the first two. Okay, cool to find the matrix. We're gonna say, match on movie where title is we specifically wrote this out as matrix, comma, the that's how I think you have it in the database. Yep. Here's the matrix. Cool. So I do the matrix. I'm not going to find it because we're just searching for an exact equality. So I get no changes, no records. And then the next question I think was can I find all the movies in the matrix series? So that's where I can change my syntax a little bit to say, where m dot title contains matrix and return m that should give me where there are three at the time this database was created or at three matrix movies. So here's three matrix movies.

13. Actors in Matrix Movies

Short description:

In the matrix movies, Keanu Reeves acted in all three, while Carrie-Anne Moss appeared in two. To find other movies the actors were in, we can expand the graph pattern and return the whole path. This allows us to visualize the graph and explore the connections between movies and actors.

Cool, okay, good. And then who acted in the matrix movies? What other movies were they in? Okay, that's gonna be kind of similar to what we saw before, where we added onto our pattern. So movie acted in, or the other way rather, right? So actor acted in movies. So we want the arrow going into the movie node, and here's our actors. Oh, but I'm just returning N. Let's return everything. So Keanu Reeves is in all three, cool. Carrie-Anne Moss is in two of them. Okay, cool, so that looks right. And then the other question was, what other movies are they in? Well, and we saw that again, when we're doing Jurassic Park. So we just add on to the graph pattern that we are creating. I'm gonna switch now to finding to the whole path and returning the whole path. So here's the matrix. Here's the actors in the matrix. Here's other movies that they acted in. So we can see the graph, cool.

14. Calculating Average User Ratings for Matrix Movies

Short description:

We want to calculate the average user rating for each of the matrix movies. By executing a simple query, we can find the rated relationships and calculate the average rating property. For just the Matrix movies, the average rating is 3.83, indicating that the Matrix movies are rated better than average in the database. By grouping the results for each movie, we can see that the first Matrix movie has a higher rating than the others, with an average of 4.18 compared to 3.2 and 3.0. The results are displayed in a table view, as we are returning tabular data in this case.

What was the next question? What's the average user rating for each of the matrix movies. Well, if we take a look here in this, click on this database information slide out, this will give us some information about the data that we have. We have actors, directors, genre, movie person user. For node types, we have acted in, directed, in genre, and rated as relationship. So we wanna calculate the average of the rating. So let's take a look at this rated relationships. I just clicked on rated here in the relationships in this database. I don't know what you call this a drawer, a slide out by clicking on this database icon. And that's just executed a simple query to find 25 rated relationships. And we know this cause we looked at this earlier. But if we click on one of these rated relationships, we can see that we were storing properties. So the rating and then a timestamp as properties on the relationship. So we know that's what we wanna calculate the average of, when calculate the average of this rating property. Okay, so let's go back to the query that we're building up here. Maybe we can remove some of this. So, we know we want to do this for all matrix movies, so we're going to, maybe we'll remove this piece. We're not looking at actors and other movies. We're looking now at the movies, but then now we want this, we'll say r colon rated. And then it's a user who rates a movie. So now what we want to do is return, return and if we look in the Cypher Cheat Sheet, and if we search for, I think these are in the aggregating functions. Yeah, and aggregating function sections, we have things like count, collect some, and then also average min and max. So this is how we can figure out we have an average function in Cypher, turn the average of R dot rating. And this should give us, 3.543 blah blah blah, is the average of all movies, I deleted where in that title contains Matrix. Okay, so now for just the Matrix movies 3.83, Matrix movies are rated better than average in the database. But now this is the average across all three of the Matrix movies, right? Because we had three Matrix movies, we're not searching for just the exact title. So it'd be nice to be able to group by the results of each movie. So for each of the Matrix movies, what are the ratings? I guess I would anticipate my hypothesis is that the first Matrix movie has higher rating than the others. So in SQL, to do this, we would write what's called a groupby where we are executing an aggregating functions, in this case, average is our aggregating function. And we want to run that over groups of intermediate results. In Cypher, there is a implicit groupby that anytime we return results of an aggregating function alongside some value, that we implicitly group by that value. So if I return the title of the movie, like this as keyword, this is new, this is just aliasing the result to a new variable called movie. And then the average r.rating grouped by the distinct values of title, and let's call this average rating or something like that. And we can see that guess my hypothesis was correct the matrix 4.18 average and the others are 3.2 and 3.0. So, notice that, previously we were getting this graph representation of the results. Now we're getting a table view and that's because we're returning tabular data or returning, just rows here. Oftentimes the answer to our question is a table, even though we are traversing the graph to get those results. So depending on what data we're returning, if it's graph data we'll have a little graph visualization and if returning tabular data will work with tables.

15. Building a GraphQL API with Neo4j GraphQL Library

Short description:

When generating movie recommendations, we can use collaborative filtering or a content-based approach. In this case, we'll focus on the content-based approach, using genres to recommend similar movies. By modifying our query, we can find other movies in the same genres as The Matrix movies and order them by the number of overlapping genres. The top recommendations for The Matrix movies are The Three Musketeers, King Kong, Total Recall, Godzilla, and more. We'll use this content-based approach to build a GraphQL API that exposes the recommendation database. We'll also add custom logic to show personalized recommendations based on user ratings. The Neo4j GraphQL library is a tool that makes it easier to build JavaScript GraphQL APIs backed by Neo4j. It addresses issues like the N plus one query problem and reduces boilerplate code for data fetching. The library supports GraphQL first development, allowing us to use GraphQL type definitions to drive our database data models.

Okay now this last question, what movies would you recommend to someone who likes the Matrix? Well, this question is getting at a common sort of use case that we have for graph databases, which is recommendations or personalization. And we see these on eCommerce sites. So users who bought this book also have bought these other books. So we're gonna add, give those as a recommended product that the user might be interested in. And when we're generating these recommendations, there's a couple of different ways to approach this. There's the category of what's called collaborative filtering, where we're looking at user interactions in our data sets. In this case, we have user ratings. So we're looking at user ratings to help us determine what would be a good recommendation. Basically, the approach here is to find similar users based on my rating history and what are similar users to me purchasing. Another approach would to be, would be to look at content-based options. And in this case, we have things like the genre of the movie, the director, the actors. So, if I like movies of a certain genre, recommend me more movies of those genres. So, let's take a look at how we could modify this query to... Let's look at the content-based approach. So, I like The Matrix movies. What are other movies that might be a good recommendation for me? So, we can get rid of our user rated here. And we'll do a fairly simple query here. So, in-genre. So, this is basically, go ahead and return that. This is saying, find the genres of The Matrix movies and things like sci-fi, action, thriller, adventure. Well, to recommend other movies, we just traverse out. Traverse out. Now, following that incoming in-genre relationship, and we'll call these our recommendations. So... Rec.title is gonna be our recommendation. And we can use another aggregating function here called count to count the number of overlapping genres. We'll say count star as score, and it's ordered by score in descending order. Cool, so here's our recommendation. So if we like the Matrix movies, the top recommendation is The Three Musketeers, followed by King Kong, Total Recall, Godzilla, and so on. I don't know. I'm not sure how good those recommendations are. What do you all think? That's a simple content-based approach. We're gonna use this idea. Maybe we'll try the collaborative filtering one when we get to adding custom logic to our GraphQL API. So what we're gonna do now is build a GraphQL API exposing the data in this recommendation database. And we're going to see how to do that using the Neo4j GraphQL library. And then we're going to add custom logic to that to be able to show personalized recommendations so that if I like a certain movie, show me other similar movies based on user ratings in the database. And let's talk a little bit about the Neo4j GraphQL library. So we talked a little bit about sort of the approach of building GraphQL APIs by first defining our GraphQL type definitions that defines the data that we're working within our GraphQL API. And then we write resolver functions that define the logic for how to go to our data layer to either search for data in the database or to create data for these mutations. We saw a couple of issues that came up. One was this idea of the N plus one query problem where because of the nested way that resolvers are called we make multiple requests to the data layer or honestly, there's a lot of boiler plate code, a lot of boilerplate data fetching code for fetching things from the data layer which can be a bit of a drag on developer productivity if I'm wanting to get something up and running fairly quickly. I wanna focus on areas of my app but I have more competitive advantage like adding custom logic, these sorts of things. And so to address those issues, I would say the boilerplate and performance aspects specifically there's a whole crop of tooling. So database GraphQL integrations and one of those is the Neo4j GraphQL library that makes it easier to build JavaScript. So specifically Node.js JavaScript GraphQL APIs backed by Neo4j. So we're not talking about querying the database directly with GraphQL, we're talking about a library that we use alongside our GraphQL server code to build that API layer that sits between the database and the client. So let's talk a bit about the high-level goals of the Neo4j GraphQL library. The first is to support this idea of GraphQL first development, where we start with GraphQL type definitions, and those type definitions can then drive our database data models. So we don't need to maintain two separate schemas, one for our API, one for our database.

16. Neo4j GraphQL Library Overview

Short description:

Instead of having a one-to-one mapping between the API schema and the database, we can configure the data model using schema directives. The Neo4j GraphQL library auto-generates common GraphQL API operations based on the type definitions, including CRUD operations, field arguments for ordering and pagination, and support for data types like date time and geospatial data. At query time, the library translates GraphQL requests into database queries, addressing the N plus one query problem and eliminating the need to write resolver functions. Custom logic can be added using Cypher statements and the cypher schema directive. The Neo4j GraphQL library is used with Node.js GraphQL server implementations like Apollo Server or GraphQL Yoga, and requires the Neo4j JavaScript Driver and the GraphQL JavaScript implementation as peer dependencies.

Instead, we're letting GraphQL, the type definitions, define both the schema for the API and the database. Now we'll see where we can configure the data model for the database using schema directives. So it's not the case where we want to have an exact one-to-one mapping all the time. Sometimes we want to have some configuration options or some nodes we don't want to expose in the database and so on. So we'll see how we can configure those using schema directives.

The next high-level goal of the Neo4j GraphQL library is to take those type definitions where we've described just the types, the fields on those types, how those types are connected, where we've described that basic graph, and then auto-generate all of the common GraphQL API operations that we would need to work with that data. So these are the crud, create, read, update, delete operations, so the query and mutation fields, but then also all of the little pieces that go along with that. So the field arguments to support ordering and pagination and complex filtering, and also adding the types for things like date time or the geospatial data types, adding functionality for aggregations, these sorts of things are generated from those basic type definitions and added to the API schema.

Then at query time, the Neo4j GraphQL library is able to take any arbitrary GraphQL request and translate that into a single database query in this case Cypher, and that is important for a couple of reasons. One is we're able to avoid that N plus one query problem. So we basically make one requests to the database and a graph database like Neo4j is optimized for traversing the graph, so from one node to any other that we're connected to, which is the equivalent of the nesting in our selection set. So oftentimes our GraphQL queries, because we're fetching all of the data to, for example, render a view in our application, we can often have lots of nested structures in our selection set that would be equivalent to a lot of joins in a relational database, which can have some performance issues when I have a lot of data and a lot of joins, things start to break down. But a graph database, that's exactly the thing graph databases are optimized for these traversals through the data graph. So that's one benefit is addressing this N plus one query problem, letting the database optimize that traversal through the data graph. But the other big advantage here is this means that we don't need to write these resolver functions because the database queries are generated at query time, that's taken care of for us. So big developer productivity boost here that in order to get started, we basically just need to define GraphQL type definitions and point the package at our database.

Now we mentioned a few times this idea that we want to be able to add custom logic to our GraphQL API so far, we've just seen sort of basic CRUD logic. But here's an example where we have taken a Cypher statement. So this comes from a business reviews. Actually, I think this is an example from the full stack GraphQL book, where we have a site about businesses and user reviews of businesses. And we've added a recommended field on the business type that's gonna return a list of businesses. And so here we're traversing through user reviews to find similar businesses. So a recommendation query, kind of similar to the one for the Matrix movies that we wrote just a moment ago. Now this cypher schema directive, so you can see here, the syntax is at cypher and then a statement argument and that is our cypher statement that has the logic for that query. So we said earlier that schema directives are GraphQL's built-in extension mechanism. And so we're extending the type definitions for our GraphQL API to use this cypher schema directive to attach custom logic to our GraphQL type definitions. And then at query time, this query, the cypher query that we've attached to hear the recommended field, that gets picked up in the overall generated database query. So we're still able to generate just a single database query at query time, we add this as a sort of sub query in the overall generated statement.

Okay, so how do we use this Neo4j GraphQL library? Well, it is published as a npm package. So we commonly would use this alongside something Apollo Server or GraphQL Yoga, if you're familiar with the Node.js GraphQL ecosystem. There's a couple of peer dependencies Neo4j JavaScript Driver and then the GraphQL JavaScript implementation. Here's the basic snippet. So this is kind of the minimum code that we need to get started. I think there we go, we drill in a little bit more. So first we're pulling in some package imports or pulling in the Neo4j GraphQL library, the Neo4j JavaScript Driver, which just allows us to make a connection to our database and then Apollo Server, which is I think, probably the most common Node.js GraphQL server implementation, GraphQL Yoga is another popular one, but this works with any of the JavaScript GraphQL server implementations. Then we define some type definitions. So here we have, we have movies and genres. So just a piece of the data that we're working with today. And then we have this at relationship with type and direction. So I said earlier that in the property graph model that we work with in Neo4j, every relationship has a single type and a direction. And so because of the conventions for naming that are a bit different from the property graph model that we use with Neo4j and GraphQL, so GraphQL like a field name, we're typically using a camel case like this where we start with lowercase and then uppercase every word. The convention in the property graph model with Neo4j for relationship types is to use, I think is this called snake case where we have everything in all caps and then underscores for the spaces. So encoding this information in a relationship directive allows us not to mix these conventions, but then also it allows us to capture the direction of the relationship, which we don't have that similar concept in GraphQL. So here we use that relationship schema directive to encode a bit more information. Then we create a Neo4j JavaScript driver instance with our connection credentials to our database. Here it's just running locally, username and password. Then we create a new Neo4j GraphQL instance that we're calling Neo Schema here, passing our type defs and our driver, and this goes through a schema augmentation process where we're basically generating all of those query and mutation fields, things like the field arguments for pagination sorting, filtering all of those things and generating the resolver functions. Then we pass that schema object, in this case, off to Apollo server and serve our GraphQL API. So we didn't have to write any resolver functions, those are all generated for us. Okay, so that's the high level goals of the Neo4j GraphQL library.

17. Using Query API with Bookstore Example

Short description:

Let's look at an example of using the Query API with an online bookstore. We define our GraphQL type definitions and map them to the property graph model in Neo4j. Schema directives like relationship and ID allow us to configure the API. The ID directive generates a UUID for the order ID, and the timestamp directive automatically generates the Place That field. We can also define date, time, and point scalar types in our type definitions.

Let's take a look at an example and we'll kind of walk through the Query API to see how we can use that. We're gonna look at a different example here, working with an API for an online bookstore. So we have orders, customers, addresses, books, and reviews. So you can see the graph model that this defines. So on the left, we're defining our GraphQL type definitions. And in the database on the right, that's mapping to the equivalence property graph model in Neo4j. So let's look at a couple of these directives that we're using, and some of the types that we're using. So I think these are quite interesting. In general, the way that we configure the generated GraphQL API that we want to work with is by using these schema directives. So these schema directives are really powerful. So we already talked about the relationship schema directive, where we're using to encode the type and direction that we want to define in the database. Another one we're using here is this ID directive. So in this case, we're saying that type order has an order ID, that's of type ID, it is non-nullable, so the order ID field is required to exist on every order. And by adding this ID directive, this will allow us to, anytime we create an order object, will automatically generate a UUID, so generate a random ID and store that on the order node. Similar idea for timestamp, when we create or update the order by adding this timestamp schema directive, the Place That field will automatically be generated for us. We're also working with date, time, and point scalar types that are available in the database, so those we can define in our type definitions.

18. Query API and Generated Fields

Short description:

Let's look at the query API and the generated query fields. Each type is mapped to a node label, and we get a query field for that type. The response matches our selection set in GraphQL.

Okay, so let's look at the query API, and then we'll see how we can use this for our movie recommendations data that we're working with. So let's talk through a few of the generated query fields and how we can use those. So by default, each type that we define in our type definitions is mapped to a node label, and then we get a query field for that type, but pluralized. So in our example here, we have type book, and so that maps to a books, so pluralized, because that's returning an array of books. So we can think of these query fields as kind of the starting point for a traversal through the data graph. Note that the response matches our selection set just as we would expect in GraphQL. So any fields that we add are included in this generated database query behind the scenes.

19. Query API and Neo4j GraphQL Toolbox

Short description:

We have different options for pagination, including limit and offset, as well as cursor-based pagination using the RelayConnection type. Filtering options are available in the where predicate, allowing us to search for specific criteria. We can filter nested fields in the selection set and apply filtering at the root level or based on relationships. Geo distance filtering is also supported. The Neo4j GraphQL library provides a query API for data retrieval. We can create a JavaScript GraphQL server application or use the Neo4j GraphQL toolbox, a low-code, in-browser tool for development and testing. The toolbox allows us to connect to our Neo4j Aura instance and build and test GraphQL APIs using the Neo4j GraphQL library.

For sorting and pagination, well, we saw a little bit of this early on in the first movies example dataset we were using where we have the limit. We also have offset that allows us to do pagination. And then here, we're sorting by price of books. We can also do cursor-based pagination based on the RelayConnection type. So if you've seen the GitHub API, I think is a common GraphQL API that uses the RelaySpec for cursor-based pagination where instead of specifying limits and offsets to page and say like groups of 10 or something, we get a cursor back from each query that we can use to fetch the next page based on that cursor. So we have a couple of different options for pagination available.

We saw a little bit of this, again, when we were looking at our first movies GraphQL example, but we have complex filtering options that are available in this where predicate. So here we're searching for books where the price is less than 20. And we saw that these filtering inputs are generated for each field on each type. And it's based on the type of the field. So for string fields, we have the string comparison operators for numeric fields. We have things like greater than, less than and so on. We can use this filtering nested in the selection set. So here we're searching for books with a price of less than $20 and then for the reviews of those filtering out reviews or only showing reviews that were created after a certain date. So note though that this filtering, when we include the filter arguments in a nested piece of the selection set, the filtering is applied at the level where we've inserted it. So we're not filtering books. We're getting all the books that are less than 20, but then the reviews is where the filtering is being applied in this case. We'll see an example where we can have the filter applied at the root level. We can also search by geo distance, a radius distance. So in this case, we have addresses that have a latitude and longitude here, we're searching for address nodes that are within a kilometer of a certain point and that's available on any of the point types in the API.

So here's an example where we are applying the filtering at the root level based on a traversal through a relationship. So in the previous example here, where we have this filter on the reviews field, the filtering is being applied at the reviews field. So not at the books, the books we're getting any books with a price less than 20, and then we're excluding some reviews. But what if we want to find orders that are within a kilometer or the address for the order is within a kilometer of this point. So address is its own node connected to the order. So in this case, we have a ship to relationship to a traverse. So we basically just move up that filter to the route level, but we specify the relationship that we want to traverse for it to apply. So we wanted to apply to the ship to address. And here we have the location less than distance one kilometer from this point. So now we're only going to find orders where the ship to address matches this distance filter. And we can apply this nested logic, not just with distance filters, but any of the filter arguments.

Okay, so that's a quick look at the query API. We kind of skipped over the generated mutation API, but that's okay. We'll see some examples of that in a minute. So let's get back to some hands-on stuff. Let's take a look at a couple of different ways to use the Neo4j GraphQL library. So one way is, we saw some code snippets. We can create a JavaScript GraphQL server application using something like Apollo Server, GraphQL, yoga, or we can use the Neo4j GraphQL toolbox, which is a low-code, in-browser tool for development and testing GraphQL APIs with Neo4j. So let's start with that one, the Neo4j GraphQL toolbox. So this is a hosted web tool. I'll drop a link to that in the chat here. So question from B, how do we know the distance is in meters and not feet? Oh yeah, that's a good one. So we know that simply because that is the convention used by the distance function in Neo4j. So it's specified in the documentation that that is the default unit. And I think that's also specified in the GraphQL documentation as well, if we dig into that. So yeah, SimplyConvention, that's how we know that. Yeah, good question. Cool, so let's use the Neo4j GraphQL toolbox to connect to our Neo4j Aura instance that we created in the previous exercise. And let's see how we can use that to develop and test a GraphQL API using the Neo4j GraphQL library. So Neo4j GraphQL toolbox, I dropped a link in the chat, graphql-toolbox.neo4j.io.

20. Using the Neo4j GraphQL Toolbox

Short description:

The Neo4j GraphQL toolbox is a neat tool that allows us to generate a GraphQL API and test queries against a database without creating a GraphQL server. We can open the toolbox app, enter our connection credentials, and generate type definitions based on the data in our Neo4j Aura instance. The generated GraphQL API can be tested in the browser using the GraphiQL interface. We can run queries against the database, even without a running server, and see the generated cipher statements in the developer tools.

It's also right here on the screen. This is a neat tool. It's currently in beta. So the naming and features are not finalized, but I thought it would be worth exploring because it's a great way to kind of get our hands dirty quickly without having to write much code. And basically what this does is bundle the Neo4j GraphQL library in a way that allows us to sort of generate a GraphQL API and test queries against a database without actually creating a GraphQL server.

There are some exercises defined here. Basically what we want to do is open up the toolbox app and put in our connection credentials for our Neo4j Aura instance that we created. So, hopefully we saved those connection credentials. And then the first thing that's gonna pop up is an option to generate type definitions by inspecting the database. And initially we're gonna hit cancel and just use, there's like a default movie type that we're gonna use. And I wanna start with that because that's gonna simplify some things for us. So then, there's basically, if we look at, look at maybe I'll just go through this to make it a bit more clear what we're doing. So, a graph QL dash toolbox. And the first thing I need to do is put in my connection credentials. So, if you downloaded the.env file, that will have your connection URI or we can go back to Aura. Where's my Aura instance? Oh, I got... I get logged out, let's log back in. So, there's another way to find our connection URI, which is this part right here. So in the Aura dashboard, there's connection URI for your instance, we can click that little icon here to copy it. That's the connection URI I want, and then the password, hopefully, you save that. I saved mine over here somewhere. There it is. But it's also will be in that.env file. If you downloaded the.env files, paste that in, hit connect, and then you'll see this generate type definitions. This is basically saying that there's data in the database and we can generate GraphQL type definitions to match the data in your database. I'm gonna hit cancel because I want to start simple and see this mapping a bit more clearly of how we define type definitions to drive the database. Starting off, we should see just this single movie type with just one field, title, it's a string, which happens to match the data that we have.

If I hit build schema... So now taking me to a different view, and you see, we toggle back and forth over here between type definitions and query editor. But that build schema step, by clicking that, basically that is generating the GraphQL API. So going through that process of adding the query and mutation fields, adding the arguments for filtering, pagination, these sorts of things on a fairly simple API. Just the type movie with a single field. But we can see what is generated for us. So we're using in GraphQL toolbox, the Explorer integration for GraphiQL that combines this idea of showing us the documentation and giving us just kind of a one click option for writing our selection set. Which can be kind of nice. And then I can click this little play button to run this query. And so this runs against the database. Give back my 10 movies. So this runs against the database, even though no servers running, it's all kind of managed in the browser. If I go to the developer tools, so let's go to the JavaScript console. And if I run this query again. Do I need to turn on debug mode? Where is that? Oh yeah. Enable debug. So here we see a show is the generated query. So if we go back to type definitions and enable debug mode, now when I run the query we should see, oh do I need to hit build schema again, maybe? Debug mode build schema. There we go. So if we enable this debug mode, hit build schema again, then when we run the query we'll see the generated cipher statement. Let me zoom in on this. So that debug mode will show us the generated cipher statement before it is executed. So in this case, we generate this cipher statement.

21. Updating Type Definitions and Introspection

Short description:

We will update our type definitions to include actors and query who acted in Jurassic Park. Then we will explore the introspection feature. Pause for a few minutes to allow participants to work through the steps. Next, we will look at writing a JavaScript Node.JS GraphQL server application and adding custom logic for personalized recommendations.

So it's fairly simple match movie, return limit 10, but that's helpful to see what is being generated in terms of database queries. Okay, so that's the basic idea. So there's a few things to work through here. One is query to find all movies and then find just Jurassic Park. Well, we can do that one now. This is very similar to what we did before, so that's fine. So we're gonna add... Actually, let's do it by clicking through on explore. So we know this is gonna be a where, where title is, Jurassic Park. Let's run that. Here's our movie. And now we can see the generated Cypher statement includes this Jurassic Park predicate where this dot title is Jurassic Park. Okay, so now though, what we want to do is update our type definitions to include actors and query to find who acted in Jurassic Park. And there's a reminder here to use the relationship schema directive with a link to the documentation. So, basically, what we want to do here is just kind of go back to the type definitions and edit our type definitions here to include the actor type and the connection between actor and movie so that then we can write a query to say, find everyone who acted in Jurassic Park. And that point is just to get across how we define our type definitions to drive the GraphQL generated API. And then once we've done that, then we're gonna check out this introspection feature and see how that works. But let's stop here for a couple of minutes. We'll give folks time to work through these couple of steps here. So if you haven't already opened up this GraphQL toolbox, connect it to your Aura instance using the connection credentials, and then first hit cancel, don't use the generated type definitions. See how the GraphQL toolbox tooling works, and then we'll write some queries and take a look at that. So we'll pause here for a couple of minutes and then the next thing we're gonna look at is sort of the equivalent of this but actually writing a JavaScript Node.JS GraphQL server application. And then we're going to take a look at custom logic and adding the personalized recommendation feature to our API.

22. Adding Actors and Inspecting the Database

Short description:

We added the actors type in our type definitions and added the relationship directive to allow querying from the movie to the actors. We wrote a query to search for Jurassic Park and see the generated cipher statement. However, we need to add a relationship field to the actor type to see what movies the actor has acted in. We can now see what other movies actors have acted in. We can also use the introspection feature to inspect the database and generate GraphQL type definitions for all the data. We noticed an interface called active and properties, which uses the relationship properties directive. This is a different way of modeling relationship properties in GraphQL using the relay connection type. We model the properties using the relationship properties directive, which gets mapped to relay connection types.

What we wanted to do here was start off with just the movie type and we wrote some queries, we saw how the arguments for filtering are generated with just a simple field like the title. Let's add the actor type. So we know that actors have a name, we'll make that a required string. And then we wanna be able to connect movie to actor. So, we're gonna say actors is going to give us ray of actor objects. And we need, because we're using the Neo4j GraphQL library, we need to add this relationship directive for the connection between movie and actors, and that has a type argument, which is gonna be acted in, and direction, which is an enum, so two options in or out. And so the way to think about this is, well, it's acted in, so we're going from the actor to the movie, the actor acted in a movie, so in that case, that's gonna be coming in to the movie type. And now if we head build schema, we get this error that says, let's type relationship fields must be non nullable and have non nullable entries. And that's just saying that this needs the explanations. And the reason for that is that we will always return an array from this actor and that's called an actors field. It may be an empty array if we don't have any actors connected to this movie, but we're not gonna return null. And then inside the array, the only thing that will be inside the array are actor objects or actor nodes from the database. And so that's why we have the inner non-nullable, we're never gonna return an actor, an actor, and then a null inside the array. So that's just some type checking to make sure we do a good job there. And now if we look at the generated fields here, we have actors and on the movie type as well, we have an actors field. So let's add actors and the name, and then for the movies, we want, are we searching for Jurassic Park here? I think that was the, there we go, that was the assignment. So who are the actors of Jurassic Park? Well, we've seen this one. So just to recap, if folks couldn't quite hear me, we added the actors type in our type definitions here and we added the relationship directive here on the actors field and movie to allow us to query from the movie to the actors. Then in our query, that allowed us to write this query to search for Jurassic Park. Who are the actors of Jurassic Park? Cool. And we can see here the generated cipher. So now the cipher, the generated cipher statement includes this traversal from actor to the movie. So you can see first the filtering is applied to find the movie, Jurassic Park. And then we have this connection from movie to the actors. Cool. One thing to note here is that this doesn't give us the ability to go from an actor node to see what movies the actor has acted in. And to see that we would need to add a relationship field to the actor type as well. So that would look something like this. Now the same relationship types going to be acted in and this time the direction is going to be out going. So like that. Now we could go from, actually if we hit build schema, we can test this because now for the actors, we can now see what movies they, what other movies they have acted in. So here are the other movies that Jeff Goldblum has acted in. So cool, and I think the last question on our exercise here, is now select the introspection button, which we could have done the first time. So as we go back to type definitions, we have this option here introspect, it says this will overwrite your current type definitions. That's fine. We're now inspecting the database. So we're looking at the data model in the database and generating the GraphQL type definitions for all of the data in the database. What's cool, we can see here though, there's a few things that we haven't seen before and some things that we read a little bit funky that we might wanna tweak before we actually use this. So one thing that we see right away is there's an interface here called active and properties. It's now using this relationship properties directive and what's going on here is in our property graph model and we should have one of these for the rating as well. Let's look at the rating one. That's one that we actually use. Here, we have rated properties. That is the relationship properties. And what's going on here is that because we, in the property graph model we stored the rating as well as the actor's role in a movie. That's information that is relevant for the relationship or the connection between two nodes. And so we have a different way of modeling relationship properties in GraphQL. We use the relay connection type which introduces the edge type, if you've seen this before, to work with meta information about the connection between two types in GraphQL, that's a good use for the relay connection type. And so in order to define those, so what are the properties that we've stored on relationships? For that, we model that using this relationship properties directive, which then gets mapped to relay connection types. So that's one thing we haven't seen before.

23. Additional Labels and Schema Generation

Short description:

In GraphQL, we can store multiple labels on a node using additional labels directives. The actor two type is generated for nodes that have both the actor director and person label, but we can remove it. The introspection feature is powerful for generating a GraphQL API based on existing data, but we can tweak it using GraphQL toolbox. The full generated schema can be viewed after building the schema.

The other thing we haven't seen before are these at node additional labels directives on actor. Well, we said earlier that in the property graph model, we can store multiple labels on a node. So for example, actor also has the person node to indicate that this is a person similar for director and so on. And so in GraphQL, we have a directive to add that additional information to capture that additional label there. You'll also know we generate an actor two type, and this is because there are some nodes that have both the actor director and person label. So that gets added as a separate type, which we don't really need so we can remove that. We can remove the acted, two acted in to connect the movie type. And then things like this actors acted in the introspection function uses some convention to basically encode the relationship type and the type of the other node that we're connecting to. So we don't need to be that for both. We can just say, this is the actors field here and similar user ratings as maybe a better way to word this. So you can see that that introspection feature is really powerful when I have existing data in the database and I want to generate the GraphQL API based on that. But oftentimes, it's something that's generated something that we might want to tweak a little bit which we can do in GraphQL toolbox. So now if I hit build schema, now we can see the full schema that is generated for us.

24. Connecting Aura to Node.js GraphQL Server

Short description:

Let's connect our Aura instance to a node.js GraphQL server using a code sandbox. Code sandbox allows us to run and edit JavaScript code in the browser. We'll update the.env file in the sandbox to point to our Aura instance and write queries to test the connection. In the sandbox, we use the Neo4j GraphQL integration, Apollo server, and the Neo4j driver instance. We generate a fully functional GraphQL API from our type definitions.

Cool, so we've got 45 minutes left. Let's move on to the next exercise which is connecting our Aura instance to an actual node.js GraphQL server. So in this case, we want to actually write some code that has the logic for our GraphQL API rather than using the GraphQL toolbox. And the toolbox is nice for testing and development, but it doesn't give us a graphical API that we can deploy somewhere.

So for this one, let's take a look at a code sandbox. Code sandbox allows us to run JavaScript code in the browser, so in this case, because it's node.js code, it spins up a container for us and allows us to run and edit code in the browser. You can sign in to code sandbox with GitHub and fork the sandbox to make it private to you. We'll update the.env file in the sandbox to point to our Aura instance, and then we can write queries to test the connection to our database.

Once we're connected, we can explore the code in the sandbox. We're using the Neo4j GraphQL integration, Apollo server, and the Neo4j driver instance. We read our type definitions from a schema.graphql file, create a Neo4j driver instance, and then create an instance of the Neo4j GraphQL package with our type definitions and driver. We generate a fully functional GraphQL API from the type definitions, including resolver functions.

25. Updating Database Connection and Testing Queries

Short description:

We update the database connection to point to our Aura instance by replacing the environment variables in the.env file. After saving the changes and restarting the sandbox, we can write queries to test the connection and retrieve movies from the database.

And there's kind of a dummy database connection in there already. So we wanna update this to point to our Aura instance. And I grab the connection URI, replace that environment variable here. So this is.env file, this is setting environment variables. So in this case, the like secrets, the things that I don't wanna check in to version control. So the user is gonna be Neo4j. And then the password I saved, there we go that's my password. So I'll save that. And that will restart my sandbox. And now I should be able to write some queries. So let's try a simple one, oops, movies options. Let's do just a limit 10, just a test that we're connecting to our database, pulling in some movies, access on. Well, let's restart that. So I think maybe to restart that after we update our connection credentials, tracing query plan, don't need that. Nevermind, let's restart the whole container.

26. Connecting Code Sandbox to Aura Instance

Short description:

I want to show what this looks like to run outside of toolbox, connected to our Aura instance. We're pulling in the Neo4j GraphQL integration, Apollo server, and the Neo4j driver instance. We read our type definitions, create a Neo4j driver instance, and generate a fully functional GraphQL API. We can explore custom logic and authorization. We have about 30 minutes left to cover everything.

The point I want to share here is really to show, here we go, to show what this looks like to run outside of toolbox, connected to our Aura instance. So I'm getting this error message, is accessed on database Neo4j is not allowed for user recommendations with roles public. And that is expected, that is the expected error to get for the previous data that I had loaded in here. But I think did we not properly restart the container perhaps. I'm gonna go to restart sandbox. Let me go back to the container. So I think it did not pick up my changes perhaps to the.env file. And we don't need this database, but we're just using the default database. While we're waiting for that to restart, let's take a look at the code that we have in here. So we'll do it with index.js. So what's going on here? Oh, yeah, there we go. So now I restarted the sandbox to pick up my changes to the.env file. And now we're connected to my Aura instance. So that looks good. But let's look at the code. So this is similar to the code snippet we saw before, perhaps just with a few extra pieces. So we're pulling in the Neo4j GraphQL integration, we're pulling in Apollo server. We're pulling in the Neo4j driver instance. A couple of helpers, one, fs allows us to read from the file system,.env allows us to read that.env file and set those environment variables. We are reading our type definitions from this schema.graphql file. And this should look similar to the type definitions we were working with in Playgrounds, it's a simplified version, I'm not including all the relationship properties and things like that. So we read those environment or those type definitions, we create a Neo4j driver instance, using our environment variables, we create a instance of the Neo4j GraphQL package with our type definitions and driver. And then we go through the schema generation process, so that's taking our type definitions, generating a fully functional GraphQL API from that, and then that includes generating our resolver functions. And then we pass that to Apollo server. I'm also pulling in the Apollo server plugin that just allows us to use GraphQL playgrounds, instead of which is now, now the default is Apollo studios just trying to be consistent with our using of tools there. So Rafael is asking with Neo4j schema can we also use the envelope framework? I'm not too familiar with envelope. That is the GraphQL guilds tooling for... What is that exactly? Is that for combining GraphQL services? Oh, for plugins. I'm not sure I haven't used this myself. So that is the answer. Not sure. Good to try though. I will add it to the list. I would imagine... I mean, basically all the Neo4J GraphQL library is doing is generating resolvers from type definitions, combining those to create a Neo4J GraphQL schema object, so an executable schema object. And it has then gives you that object to then work with, which follows the GraphQL spec and all of these things. So you should be able to use that schema object then with other pieces of tooling from the GraphQL ecosystem. So, not sure specifically about envelope. But also for extending the context. Okay, so you can have more information injected in the context object then with envelope. Okay, cool. Yeah, yeah that would be one to try. I'm not something I've tried. Cool, so that is a look at connecting our code example running in Code Sandbox to our Aura instance. I had an exercise for this one, maybe we'll skip that and just talk a bit about custom logic and maybe we'll talk about through authorization as well. We have about 30 minutes left. Make sure we can cover everything, and if we don't have time to work through some of the exercises that can be maybe some things to play with afterwards. Cool, so let's talk about custom logic in our GraphQL API. So far, we've just seen sort of what we call CRUD, create, read, update, delete, that sort of basic functionality for generating a GraphQL API. But we haven't seen how to add custom logic.

27. Adding Custom Logic with Cypher and Resolvers

Short description:

We can add custom logic beyond basic CRUD functionality in the Neo4j GraphQL library using the at-Cypher GraphQL schema directive or by implementing custom resolvers. The resolvers may involve multiple round trips between the database query and the custom resolver, especially when interacting with external systems.

Maybe we have some business logic. I always like to use the example of recommendations, right? Because that's something that can apply to lots of different domains and so on. But this can really be any sort of custom logic beyond your basic CRUD functionality. And there's two ways to do this with the Neo4j GraphQL library. One is, use the at-Cypher GraphQL schema directive. So we saw an example of this when I was talking about the features of the Neo4j GraphQL library that allow us to take custom Cypher statements, bind those to our GraphQL schema. And then those statements are included in the single generated database query. And then the other approach is, we can always implement resolvers. So we can implement custom resolvers and then include those in our GraphQL server and have those resolvers called alongside the generated resolver. The thing to be aware of here is that those resolvers will still be called in that nested fashion. So we may end up making multiple round trips between the generated database query and our custom resolver. But this is common if we have another system that we need to call out to outside of Neo4j.

28. Using Cypher Directives and External Systems

Short description:

We can easily define the subtotal logic in Cypher by matching the order and summing the book prices. The recommended field on the customer type returns other books that users have ordered. We can also return objects from external systems using Cypher procedures, such as calling a weather API to fetch data for the address node. The returned objects can be projected from data and added as additional fields in the GraphQL API.

So let's look at some examples of using this Cypher directive. So we're gonna go back to looking at the Bookstore API example that we saw earlier. So here we're adding a subtotal field to the order type. So remember we had orders and orders were connected to books. We could place one or more books in an order, but it'd be helpful to know what is the subtotal. So what is the price of every book? Add those up. That's the subtotal of our order. And so we can easily define that logic in Cypher with the Cypher statement, you match on this. So with the Cypher directive, there's a variable, this, that is automatically defined in these Cypher statements. And this refers to the currently resolved object. So in this case, this refers to the order that we are currently resolving, similar to the first, I think the first argument passed to a resolver, which is the object that we're currently resolving. But anyway, that's available in the Cypher statements here with the, this keyword. So match where this order contains books, return the sum of the book price that gives us the subtotal, which here we've indicated is a float field. So once we've defined that in the schema, then that subtotal field is available just alongside all the other fields. There's no indication to the client of the GraphQL API that there's anything special about this field. So we can return scalars from the Cypher statements. So we can return a string, we can return an integer, we're returning a float in the previous one. We can also return nodes or objects. So here's the recommended field, which I like to use as an example. So here we're adding a recommended field on the customer type. So a customer based on their purchase history, what are other books they may be interested in you can see the query they were using here goes through their orders, their orders contain books. What are other orders placed by other customers that contain books that this user did not order? Those might be good recommendations. So of the people reading the books that I'm reading, what other books are they reading that I haven't read yet? That might be a good recommendation. That's basically what the cipher query is saying. But the important part here is that we're returning REC, which is, you can see here, REC is one or more book nodes. So we indicate here in our GraphQL type definitions that recommended is resolving to an array of book objects. And to make that work in the cipher statement, we just return node objects. So I'll just type a little bit of code into this. And here, we are searching for customers recommended books. We get an object field. So we need to select the title from that. We can use field arguments with the cipher directive fields. So any field arguments that we add in the type definitions are passed to the Cypher statement as cypher parameters. So here we've added a limit argument, which is an integer, setting a default value of three. So this allows us to specify the number of book recommendations to return. So here, we're saying we want to return by default three books, but at query time, we can change this. It's useful to know here, if we go down this path, it's helpful to set default values for these field arguments, because we then will know that they're always defined when we're writing our Cypher statements as cypher parameters. So here we specified. We just want one recommended book. Now we can also return objects that are not actually stored in the database from a cypher directive field. And this sounds a little odd, but this is something we can do. Oftentimes, maybe we want to change the shape of the data that we're returning, or in this case, as example, we're calling out to an external system using a built-in cypher procedure. So cypher has a standard library called APOC that adds some additional functionality to the query language, and one of those procedures allows us to call out to other JSON APIs. So here, we're doing an APOC load JSON calling out to this weather API, and so in this example, for our address, so the idea is for our delivery drivers that are delivering orders, orders are connected to an address node, and on that address node, we want to add this weather object that is going to tell the driver what the weather is at that address. So we add a new type, weather that has things like temperature, wind speed, precipitation, these sorts of things, and then we're calling out to an external weather API to fetch that data. And when we return that, you can see in the return clause in our Cypher statement, this is a function of Cypher, we haven't talked about yet, but we can return objects or maps or dictionaries that sort of are projected from data. And so in this case, we're returning a weather object, even though that doesn't map to data that we've stored in the database, as long as we've defined that in our type definitions that will work with GraphQL. And again, that's added as an additional object field on the address type here so we can see the weather for these various orders.

29. Custom Logic and Resolvers

Short description:

We can use Cypher directives on query and mutation fields to create a full-text fuzzy search and add custom logic to mutations. For example, we can write a custom resolver to add an estimated delivery time for an order. By using the ignore schema directive, we can tell the Neo4j GraphQL library to ignore this field and use the custom resolver instead.

So, so far the fields we've added have been fields on types like book, or address. We haven't seen custom root level query fields or mutation fields. But we can use Cypher directives on query and mutation fields. So here we're creating a full text index in the database and then adding a query field. So a new root level query field to do a full text fuzzy search. And this is a bit of a contrived example because we can actually use a directive to enable full text search with Neo4j GraphQL library. But if we had some other logic for defining root level queries, this allows us to do fuzzy matching against the title of book. So here we misspell the title of the book and it uses a full text index to find any matchings. And we can do the same thing for mutations. We didn't talk much about the mutation API that is generated when we use Neo4j GraphQL library. But it follows the convention that we generate a create update and delete for each operation, for each type that we define. But if we want to have some more custom logic, we can take an input object and then define a cipher how we want to handle that data in a mutation. And then, as I said earlier, we can use the cipher schema directed or we can write custom resolvers. So here, we've written a custom resolver to add an estimated delivery time for our order. This, again, is quite contrived because this is just a JavaScript function to find that at random. But imagine that we had a more complex logistics system or something like that where we had to write some custom code to call it to that system. We write the resolver function, and then in the type definitions, we add this ignore schema directive so that we are basically telling the Neo4j GraphQL library that we're going to ignore this field. We're not gonna try to fetch it from the database. We're writing a custom resolver to find that.

30. Authorization Functionality and Rules

Short description:

There is authorization functionality built into the Neo4j GraphQL library. It uses JSON web tokens (JWTs) to define authorization rules for protecting data. The JWT contains claims such as user ID, email, and roles, which are cryptographically signed by the server. The JWT is passed as an authorization header in the GraphQL request, and the library decodes it to apply the claims to the request. The library provides directives like ISAuthenticated, Roles, and Allow to define different authorization rules based on the JWT. These rules ensure that only authenticated users with the necessary roles can access protected fields or types in the GraphQL API. The library also allows matching values from the JWT with values in the database to control access to specific information. Instead of throwing an error when a user requests data they don't have access to, the library can return only the data the user is authorized to see.

Okay, so we have an exercise for this to add a similar field to the movie type. I think we have 20 minutes left. I think what we'll do instead is we'll leave this as an exercise, and instead we'll talk a bit about authorization. And I'll just talk through this and then answer any questions that folks have. So if you have any questions, drop them in the chat, and anything we didn't cover, I'll try to address and at least find follow-up links to share with folks. But let's talk through some of the authorization functionality and then we can answer some questions at the end here.

So there is some authorization functionality built into the Neo4j GraphQL library. It's powered using another schema directive. So these schema directives are really quite powerful. I think, the documentation, yeah, here we go. This page in the documentation lists all of the schema directives that are available. And like I said, this is how we can configure the generated API for the Neo4j GraphQL library. In the auth directive, let's take a look at the docs. The auth directive, here we go, this is how we define authorization rules for protecting data. So ensuring that only users that should have access to data are able to access it through our API. So the convention with the auth directive is we use JSON web tokens, or JWTs, or JWTs as they're commonly called. And the idea with a JSON web token is we take a JSON payload that has what are called claims. And so this can be things like the user ID, the email, the roles that the user has. And then those claims are cryptographically signed by the server. And we can then verify that those claims are accurate, that those are valid claims in the JSON payload, because we can verify that that was cryptographically signed by our application. And so we pass this JSON web token as an authorization header in the GraphQL request, and then you have to GraphQL library will then decode that JSON web token and apply those claims to the GraphQL request. And here's an example, it's just showing a encoded JSON web token and the JSON payload that is available. And you can find these oftentimes if you go in to your browser network tab, you can see some of these tokens that are used in a lot of web applications, you can copy the token, paste it into a tool like this or decode it and see what claims are in there. It's kind of interesting thing to do. So you don't need the cryptographic key to decode a JSON web token, you can always read the claims are in it, but it is signed so to know that those claims are verified by server.

So let's talk through a couple of the Auth rules. And again, this is for the book API that we're looking at. So the simplest Auth directive rule is called ISAuthenticated. And this just means that the GraphQL request contains a valid signed JSON web token. So in this case, in order to access the subject type, so books have a subject, in order to access that, the user just needs to be authenticated. And the use case for this might be in your web application, you show some basic information to unauthenticated users, but if they want the more detailed information, they need to at least register and sign into your application. So here's showing the difference when we are an unauthenticated user requesting a protected field versus the authenticated user. And here you can see how we are attaching the authorization token here as a authorization header in the GraphQL request. The next authorization rule is called Roles. And what this means is that in order to access the protected field or the protected type in the GraphQL API, the JSON Web Token must have a certain role in the Roles claim. And so here we're saying for the book type in order to do any of the mutation operations, so create, update, or delete, the user needs to be an admin, needs to have an admin role. So only admins can update or delete data. And allow is the next rule that we'll talk about. And this means that in order to access the information, a value from the JWT must match some value in the database. And in this case, we're looking at the sub claim. This is how we access the claims of the JSON web token. Use this dollar sign, JWT dot. And then the claims in the JSON payload. Sub is the convention for the subscriber in a JSON web token. So is this saying that the username stored in the database needs to match the sub, the subscriber claim in the JSON web token in the graph QL request in order to access customer orders? This is following a relationship going from the order node to the customer node, ensuring that the username matches the value in the token to be able to see the order. So here's an example where we're looking for a specific customer and their orders. And we are properly authenticated as that user. However, if we are authenticated as a different user, here we're asking for all orders, we get an error here. And this is a bit problematic because maybe the client doesn't know what data it doesn't have access to. So instead of throwing an error, what would be nice is if we ask for all orders, if we just got back whatever orders we had access to? And so that's where the next rule that we'll look at.

31. Authorization Rules and Custom Logic

Short description:

Allow in any of these rules, we can combine them. To address the issue of returning unauthorized data, we can use the where rule. It filters data based on the user's access rights. The bind rule ensures that a certain condition is met during a mutation. We can also apply authorization rules on Cypher directives, either by using rules like is authenticated and role, or by accessing the JWT payload in Cypher statements as variables. This allows us to add custom logic and perform actions based on the user's authentication status.

One more thing on allow. Allow in any of these rules, really, we can combine them. So the rules array here that we're passing in the auth directive, this is or logic. So this is saying, in order to access an order, you need to be authenticated as the user that placed that order or you need to be an admin. But to go back to the issue here, where we're returning an error because the client has requested information that it doesn't have access to without really knowing that it doesn't have access to that information. To get around that, we can use the where rule. Here we're saying in order to access customer information, the username of the customer node needs to match the subscriber claim in the JSON web token. This means that a predicate will be added to the generated cipher statement to filter out any data that the user doesn't have access to. Here we're authenticated as a user, we're asking for all customers and their orders. But because we have that where authorization rule, the generated query only is including data that the authenticated user has access to which is just that user's information. The currently authenticated user. Bind is useful for mutations. It's basically allows us to define a rule that must exist when we are executing a mutation. So here for a review, we're saying that the author of the review must be the currently authenticated user. We don't want you to be able to update, create reviews, and then say that someone else wrote it. The author needs to be the currently authenticated user. We can also use authorization rules on Cypher directives. There's a couple of ways to do that. One is, apply rules like the is authenticated and the role directive. Those will still be checked before executing that Cypher statement, or we can also access the JWT payload in our Cypher statement as Cypher variables, Cypher parameters. So here we're using the is authenticated rule on a Cypher statement. So books for current user, it doesn't make sense to try to look up books for an unauthenticated user because that would give us an error by looking up customer by this username. You can see here how we're accessing auth.JWT.sub. So this auth.JWT, this is a special parameter that we're using here to inspect the payload of the JSON web token that we've attached in the header of the GraphQL request, decoded now, injected into our Cipher statement for adding custom logic. So we look up the customer by username, and then we traverse the graph to find, what is this basically? All books, oh, this is a recommendation query. So this is all books that they've ordered, finding the subject of those books, then using the subject to find other books that they might be interested in. And so I like to use the recommendation query, it's helpful as a use case that applies across many domains.

Watch more workshops on topic

GraphQL Galaxy 2021GraphQL Galaxy 2021
140 min
Build with SvelteKit and GraphQL
Top Content
Featured WorkshopFree
Have you ever thought about building something that doesn't require a lot of boilerplate with a tiny bundle size? In this workshop, Scott Spence will go from hello world to covering routing and using endpoints in SvelteKit. You'll set up a backend GraphQL API then use GraphQL queries with SvelteKit to display the GraphQL API data. You'll build a fast secure project that uses SvelteKit's features, then deploy it as a fully static site. This course is for the Svelte curious who haven't had extensive experience with SvelteKit and want a deeper understanding of how to use it in practical applications.

Table of contents:
- Kick-off and Svelte introduction
- Initialise frontend project
- Tour of the SvelteKit skeleton project
- Configure backend project
- Query Data with GraphQL
- Fetching data to the frontend with GraphQL
- Styling
- Svelte directives
- Routing in SvelteKit
- Endpoints in SvelteKit
- Deploying to Netlify
- Navigation
- Mutations in GraphCMS
- Sending GraphQL Mutations via SvelteKit
- Q&A
React Advanced Conference 2022React Advanced Conference 2022
95 min
End-To-End Type Safety with React, GraphQL & Prisma
Featured WorkshopFree
In this workshop, you will get a first-hand look at what end-to-end type safety is and why it is important. To accomplish this, you’ll be building a GraphQL API using modern, relevant tools which will be consumed by a React client.
Prerequisites: - Node.js installed on your machine (12.2.X / 14.X)- It is recommended (but not required) to use VS Code for the practical tasks- An IDE installed (VSCode recommended)- (Good to have)*A basic understanding of Node.js, React, and TypeScript
GraphQL Galaxy 2022GraphQL Galaxy 2022
112 min
GraphQL for React Developers
Featured Workshop
There are many advantages to using GraphQL as a datasource for frontend development, compared to REST APIs. We developers in example need to write a lot of imperative code to retrieve data to display in our applications and handle state. With GraphQL you cannot only decrease the amount of code needed around data fetching and state-management you'll also get increased flexibility, better performance and most of all an improved developer experience. In this workshop you'll learn how GraphQL can improve your work as a frontend developer and how to handle GraphQL in your frontend React application.
React Summit 2022React Summit 2022
173 min
Build a Headless WordPress App with Next.js and WPGraphQL
Top Content
WorkshopFree
In this workshop, you’ll learn how to build a Next.js app that uses Apollo Client to fetch data from a headless WordPress backend and use it to render the pages of your app. You’ll learn when you should consider a headless WordPress architecture, how to turn a WordPress backend into a GraphQL server, how to compose queries using the GraphiQL IDE, how to colocate GraphQL fragments with your components, and more.
GraphQL Galaxy 2020GraphQL Galaxy 2020
106 min
Relational Database Modeling for GraphQL
Top Content
WorkshopFree
In this workshop we'll dig deeper into data modeling. We'll start with a discussion about various database types and how they map to GraphQL. Once that groundwork is laid out, the focus will shift to specific types of databases and how to build data models that work best for GraphQL within various scenarios.
Table of contentsPart 1 - Hour 1      a. Relational Database Data Modeling      b. Comparing Relational and NoSQL Databases      c. GraphQL with the Database in mindPart 2 - Hour 2      a. Designing Relational Data Models      b. Relationship, Building MultijoinsTables      c. GraphQL & Relational Data Modeling Query Complexities
Prerequisites      a. Data modeling tool. The trainer will be using dbdiagram      b. Postgres, albeit no need to install this locally, as I'll be using a Postgres Dicker image, from Docker Hub for all examples      c. Hasura
GraphQL Galaxy 2021GraphQL Galaxy 2021
48 min
Building GraphQL APIs on top of Ethereum with The Graph
WorkshopFree
The Graph is an indexing protocol for querying networks like Ethereum, IPFS, and other blockchains. Anyone can build and publish open APIs, called subgraphs, making data easily accessible.

In this workshop you’ll learn how to build a subgraph that indexes NFT blockchain data from the Foundation smart contract. We’ll deploy the API, and learn how to perform queries to retrieve data using various types of data access patterns, implementing filters and sorting.

By the end of the workshop, you should understand how to build and deploy performant APIs to The Graph to index data from any smart contract deployed to Ethereum.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

GraphQL Galaxy 2021GraphQL Galaxy 2021
32 min
From GraphQL Zero to GraphQL Hero with RedwoodJS
Top Content
We all love GraphQL, but it can be daunting to get a server up and running and keep your code organized, maintainable, and testable over the long term. No more! Come watch as I go from an empty directory to a fully fledged GraphQL API in minutes flat. Plus, see how easy it is to use and create directives to clean up your code even more. You're gonna love GraphQL even more once you make things Redwood Easy!
Vue.js London Live 2021Vue.js London Live 2021
24 min
Local State and Server Cache: Finding a Balance
Top Content
How many times did you implement the same flow in your application: check, if data is already fetched from the server, if yes - render the data, if not - fetch this data and then render it? I think I've done it more than ten times myself and I've seen the question about this flow more than fifty times. Unfortunately, our go-to state management library, Vuex, doesn't provide any solution for this.For GraphQL-based application, there was an alternative to use Apollo client that provided tools for working with the cache. But what if you use REST? Luckily, now we have a Vue alternative to a react-query library that provides a nice solution for working with server cache. In this talk, I will explain the distinction between local application state and local server cache and do some live coding to show how to work with the latter.
GraphQL Galaxy 2022GraphQL Galaxy 2022
16 min
Step aside resolvers: a new approach to GraphQL execution
Though GraphQL is declarative, resolvers operate field-by-field, layer-by-layer, often resulting in unnecessary work for your business logic even when using techniques such as DataLoader. In this talk, Benjie will introduce his vision for a new general-purpose GraphQL execution strategy whose holistic approach could lead to significant efficiency and scalability gains for all GraphQL APIs.