Building GraphQL APIs With The Neo4j GraphQL Library

Rate this content
Bookmark

This workshop will explore how to build GraphQL APIs backed Neo4j, a native graph database. The Neo4j GraphQL Library allows developers to quickly design and implement fully functional GraphQL APIs without writing any resolvers. This workshop will show how to use the Neo4j GraphQL Library to build a Node.js GraphQL API, including adding custom logic and authorization rules.

Table of contents:
- Overview of GraphQL and building GraphQL APIs
- Building Node.js GraphQL APIs backed a native graph database using the Neo4j GraphQL Library
- Adding custom logic to our GraphQL API using the @cypher schema directive and custom resolvers
- Adding authentication and authorization rules to our GraphQL API

175 min
03 Dec, 2021

Comments

Sign in or register to post your comment.

Video Summary and Transcription

Today's workshop focused on building GraphQL APIs using Neo4j, a graph database. The Neo4j GraphQL library was used to generate the API, handle data fetching, and solve the N plus one query problem. Custom logic and authorization rules were added using Cypher statements and the auth schema directive. The workshop also covered filtering, sorting, and pagination options in GraphQL, as well as the integration of Neo4j with Code Sandbox and Neo4j Aura DB. Overall, the workshop provided a comprehensive overview of building GraphQL APIs with Neo4j and highlighted the benefits and challenges of using this technology.

1. Introduction to Neo4j and GraphQL

Short description:

Hello everyone! Today, we'll be building GraphQL APIs for sandboxing using Neo4j, a graph database. We'll start by discussing Neo4j and GraphQL, then explore the Neo4j GraphQL library for building APIs. We'll also cover adding custom logic and authorization rules to our API. Please note that we'll be focusing on the backend piece and not integrating the GraphQL API into a frontend application.

ReactJS, through the mouth of assistant projects and project managers. Well, hello everyone. Thanks for joining today. We are going to be building GraphQL APIs for sandboxing, which is a hosted database as a service. You don't need to set up local environments. We're going to do everything with these hosted sandbox environments. So don't worry about setting up a local environment, but we'll talk about that in a little bit.

The slides are linked at dev.neo4j.com slash GraphQL dash training, link in the chat here. I would recommend pulling up these slides as we work through this. There are several links and code snippets and things like that, that you may want to grab from the slides. So I'd recommend pulling up the slides as we go through this and just having them open in a tab. There's also the Discord, which Lara linked at the beginning. So I'll monitor both the Zoom chat and Discord as well. So that's either one. If you have questions, please just drop them in the chat, either in Zoom or Discord, and I'll try to monitor both and share links in both.

So my name is Will. I work for a company called Neo4j, which is a graph database that we'll be using today. I also co-host a podcast called graphstuff.fm. So if you're interested in graph technology and you like a podcast format, definitely encourage you to check that out. So here's our rough outline for today. We'll talk a little bit about what is Neo4j. I think since that was pretty much completely new for most folks, we will spend a little bit of time there but really we'll be focused on GraphQL and building GraphQL APIs backed by Neo4j. So we'll talk a little bit about Neo4j, then we'll talk a bit about GraphQL and how GraphQL APIs are typically built. Then we'll take a look at the Neo4j GraphQL library which is a Node.js JavaScript library for building GraphQL APIs backed by Neo4j. Then we'll take a look at adding custom logic to our API. And then in the final module, we will take a look at adding authorization rules to our API. We're gonna be building like a bookstore API. So we'll focus on the backend piece of this, not so much on what do I actually do with my GraphQL API once I have it built. Instead, we're gonna be focused on just the backend piece. So we won't cover integrating, for example, a GraphQL API into like a React application or something like that. We will be focusing just on the backend piece.

2. Neo4j Aura DB and Code Sandbox

Short description:

Today, we'll be using Neo4j Aura DB and Code Sandbox for our GraphQL API development. Neo4j Aura offers a free tier for hosting Neo4j instances in the cloud, and Code Sandbox allows us to run code in the browser without dealing with local development issues. We'll start with a Skeleton Starter Code Sandbox and work through hands-on exercises. Feel free to ask questions in the chat.

So I said earlier that we were gonna be building I said earlier that we don't need to worry about setting up a local development environment. We're gonna be using these Sandbox Cloud Services today. So there's two things that we're gonna use. One is Neo4j Aura DB. There's a free tier of Neo4j Aura. So Neo4j Aura is hosted Neo4j instances in the cloud that are private to us. There's a free tier. So you don't have to think about putting in a credit card or anything like that, which is quite nice. So we'll be using that for our database. Everyone will have the opportunity to spin up an Aura instance. And then for running the code, so we're gonna be building a GraphQL API using JavaScript. So Node.js GraphQL API application. And for that, we're gonna use Code Sandbox. So Code Sandbox allows us to run code in the browser, including Node code that runs on someone's container somewhere that they're hosting for us, which is quite nice. So we don't have to worry about dealing with local environments development issues. Each one of these modules, I should say I guess the last three modules have a link for a Skeleton Starter Code Sandbox with some starter code. So we'll start that way and then work through exercises, editing some code, writing GraphQL queries, that sort of thing. So you'll see this hands-on exercise icon on some slides. When you have that, we'll stop for a few minutes and we will dig into some exercises. So I'd like for this to be as hands-on as possible. And as folks have questions, please just drop them in the chat, either in Zoom or Discord, and we will dig into your questions.

3. Neo4j and GraphQL Basics

Short description:

Neo4j is a graph database that uses a property graph data model. It allows us to store arbitrary key-value pair properties on nodes and relationships. The query language used in Neo4j is called Cypher, which is focused on pattern matching. We'll be using GraphQL to generate Cypher queries. Graph databases offer interesting implications such as graph analytics and data visualization. They also integrate with various application architectures. In this workshop, we'll focus on building the API layer using GraphQL.

Great, so let's talk a little bit about Neo4j before we dive into building GraphQL APIs. So I think most folks said that Neo4j was new to them, which is great. I guess maybe what database technologies are folks familiar with? Have most folks used relational databases or maybe Mongo, let us know in the chat. If you're familiar with like relational databases or document databases, graph databases are similar concept, right? So, this is where we are storing, modeling, querying our application data. The difference with a graph database, like Neo4j, I should say, one of the first differences that you notice is that the data model is not tables, not documents. A data model is a graph. And when you say graph, we're talking about nodes. These are the entities in our data and relationships, connect them. Specifically with Neo4j, we use the property graph data model, which we'll talk about a little bit. Basically what that means is that we can store arbitrary key value pair properties on nodes and relationships.

With Neo4j, we use a query language called Cypher. You can think of Cypher like SQL, but for graphs. Cypher is very much focused on pattern matching. There's an example Cypher statement in the upper right of the screen there in this first line, where it says match, and then we have this graph pattern. Match is like a statement that's saying, it's like a statement that's saying, find some data in the graph where this pattern exists. And then the pattern, we draw this sort of ASCII art representation of a graph. So we have address in parentheses, those parentheses sort of like drawing a circle, that's a node. So we're saying find address nodes with an incoming registered address relationship. So you see how we're sort of drawing that arrow in brackets that's connected to an officer node, and then traversing out from that officer to entity nodes, filtering where the address contains New York. So this cipher statement is saying, find address nodes where the address is in New York, and find officers that have an address in New York, and then what entities are they connected to? This dataset comes, this query comes from the Panama Papers or the Pandora Papers dataset, which is a data journalism investigation that used Neo4j to make sense of complex offshore legal entity structures in like offshore banking. So we'll do a little bit with cipher today. Mostly, we're gonna be focused on using GraphQL and generating cipher queries from GraphQL. So we will write a little bit of cipher when we get to the custom logic section. But if you haven't seen cipher before, just wanted to show some of the concepts there this idea of graph pattern matching. So there are lots of interesting implications of using a graph database instead of like a document database or relational database. One is that we can do lots of interesting graph analytics with graph databases, because we can model our data differently and that allows us to, I think, write these very interesting queries that are sort of the equivalent of writing lots of joins and in SQL just by sort of expressing this graph pattern which was quite neat. There are also tools for data visualization which we might touch on a little bit today. And then we have lots of sort of integration. So I guess if we think of the database as being sort of the code, database touches a lot of different pieces of application architecture right? So database kind of sits at the core of our architecture but we need to be able to move data back and forth and there are lots of different sort of use cases that we may have for using a database in the first place. So from the spectrum on the right where we're talking about things like analytics and data science use cases. And then over on the left end of the spectrum where we're talking more about like operational, transactional applications that we're building. Maybe we're building like a social network or an e-commerce sites or something like that where we want more transactional operational workloads. And we're interested in things like building an API layer that's gonna sit between the client and the database and thinking about the tools we're gonna use there. So for our workshop today, we're very much on this left end of the spectrum where we are interested in building the API layer for a client application. And in this case, we're going to focus on doing that in GraphQL.

4. Neo4j Browser and Cypher Queries

Short description:

Today, we'll be using code sandbox environments and the Neo4j GraphQL library to work on the backend piece. We'll focus on the backend and not the frontend aspect. If you're interested in a full stack application, you can check out the GRANDstack starter project. Let's now explore a hands-on example using Neo4j Browser and Cypher queries. We'll work with a dataset of news articles and learn how to write queries to find recent articles based on labels and properties.

Cool, so Anthony says, familiar with SQL Server Firebase and Mongo. Great, cool. So now you can add Neo4j to that list after today. So here's some resources. The slides are probably the most important one. So there's a link for the slides in the chat, dev.neo4j.comslashgraphql-training. Let me just drop those in the chat one more time. I know sometimes chat kind of disappears and make a pain to scroll through. So that is not a clickable link. Let's try again. Dev.neo4j.comslashgraphql-training. Cool.

So like I said, we're gonna use these code sandbox environments and there's a specific link for each one. So if you open up the slides, at least have them in a tab to refer to. It'd be helpful just to grab the links and some of the code snippets and things as we work through the exercises. All the code for today is also linked here. Dev.neo4j.comgraphql-training-code. And these are the GraphQL queries that we're going to work through in some of our examples. So this might be a good one to bring up as well. And then the other things in here, so we're going to be using the Neo4j GraphQL library. The documentation is linked here. There's an overview page for the GraphQL library, it's links to example apps and other resources as well as a self-paced training that goes into a lot more detail than what we'll cover today.

So the timing for today, I should have said this is a three hour session and we're 20 minutes in. So that is the plan for today. Like I said, we're going to focus on the backend piece of this, not so much the front end aspect of this. So if you're interested in seeing how the pieces fit together for like a full stack application, including how the front end fits in. There's a starter project for what's called GRANDstack. That's GraphQL, React, Apollo, Neo4j database. So this GRANDstack starter is a good place to see just sort of how the pieces fit together in the context of a full stack app. But that's not going to be our focus today. Today we're focused on just the backend piece. Cool, so we talked a bit about Neo4j, I think maybe let's look at a more hands-on example. I'm going to bring up this one. Let's look at this example. This should be public. Let's see, I'll share the link, if I can remember the password here. I think news graph is one of the users. I'm going to add that. Yeah, so this is optional, I'm going to go through a couple of queries in Neo4j Browser here. So if you want to follow along, I'll drop a link in the chat and then the username is newsgraph and the password is also newsgraph. So this is Neo4j Browser, this is like a query workbench for Neo4j. So I write cipher queries and then I get back the results either like in a visual environment, but this is kind of the common development environment for working with Neo4j. I have data loaded in here from the New York Times API. So this is a data set news articles. So I think it's continuously running to scrape the most shared news articles each day. So we have things like articles, articles refer to topics or they're about people organizations refer to some geographic region and they have photos. So I can run db.schema.visualization to see, let's reset our styling here, there we go. So I can run this to see what my data model is. So I can see the nodes that I have and how those nodes are connected. So articles are about organizations or about a geographic region, about people. They have photos and topics. So I can write Cypher queries. Like let's say I want to find the most recent articles. I can write a Cypher statement using this graph pattern matching concept. So the pattern for this one is quite simple. I'm saying just find nodes with the label article. So when we say article nodes, what we're saying is find nodes that have the label article. So label is like a way to group nodes in the database, similar to like a table or like a collection from a document database is same conceptual level to think about these, I guess. Then we have these key value pair properties. So each article has a title, the date it was published, the URL for the article, and then kind of a description. So when we're thinking in GraphQL terms, what we're gonna do is map nodes and node labels, specifically, I guess, to types in GraphQL and how they're connected. Of course, we can write much more complex patterns. So for example, we could say, do we have any example queries in here, let's see. We've already written some interesting ones. Nope, that's fine. Let's say, let's find articles that have the topic, let's say exercise. My arrow's going the wrong way, goes this way. And again, you can, don't worry about following along. We're gonna start our Aura instance. But if you'd like to, I did link the username and password for this database.

5. Neo4j, GraphQL, and Resolver Functions

Short description:

In this query, we find the topic with the name exercise and traverse along the has topic relationship to find connected article nodes. We can visually explore the articles and their related topics. GraphQL is an API query language and runtime used to define available data and relationships. Clients can specify a traversal through the data graph and the desired data to be returned. GraphQL operations are queries or mutations starting from an entry point on special types. Type definitions define the available data using a schema definition language (SDL) and directives. Resolver functions fetch data from the data layer, such as a database or other APIs.

Okay, now we're saying find the topic exercise. So now to our pattern, we've added a few things. We've added this curly brace. So in this curly brace, we're saying, Anthony says he doesn't see the username and password. So yeah, so it's should be in the chat. The username is newsgraph and the password is also newsgraph. I can put that in discord as well. Oh yeah, let me drop this in discord as well. Web browser, news.graph.zone, username is newsgraph and the password is newsgraph. Cool, so that's a read only database user. We're not gonna use this one throughout the workshop but I do think it's helpful to have some data in Neo4j to play around with. Great, so in this query, we're saying, find the topic with the name exercise, that's what these curly braces indicate. Curly bracing the pattern are referring to property key value pairs and then traverse along this has topic relationship to find article nodes that are connected to the topic exercise and that's exactly what we get here. So here's the exercise topic node, here are all these articles that are connected and if we double click on these, we can traverse out and we can see, okay, here are other topics of this article, so this one is about golf and exercise here are other articles about golf so we can do that visually or we can add we can add more complex patterns, more pieces of graph pattern to the pattern that we're matching on so we can say maybe we wanna know what other topics these articles have so we just add to our pattern here for all the articles that have the topic exercise what are other topics that they have and you can see there's actually quite a mix here. Cool, so that's Cypher and Neo4j Browser. I think that is probably a good sort of whirlwind introduction and we can move on to seeing how this fits in the context of GraphQL. Okay, great, so back to our slides here. Great, so we've got our slide here. So, let's talk a little bit about GraphQL so we're all on the same page. I think some folks have indicated they've done some work with GraphQL. So some of this may be familiar for folks. Some of this is new, that's great too. But let's talk a little bit about GraphQL separate from working with a database separate from Neo4j sort of GraphQL concepts on their own. So fundamentally GraphQL is an API query language and a runtime I guess for building and fulfilling API requests. With GraphQL we use a type system to define what data is available in the API. So we're talking about what entities, attributes and how they're connected. So we define with GraphQL type definitions what the types are and what fields exist on those types if they're nullable, if they're non nullable. And then we also have relationship fields on a type that refer to other types. That's where the graph piece of GraphQL comes in. We're talking about how these objects are connected. Then at query time, the client is free to ask for sort of a traversal through this data graph and exactly what pieces of the data they want to be returned at query time. So our GraphQL operations are gonna specify an entry point and then a traversal through the data graph. These entry points, these are fields on special types called query or mutation or subscription. We're not gonna talk about subscriptions today. So a couple of important concepts, especially for building the GraphQL server piece of this and important concepts. So the first one is this concept of GraphQL type definitions. So type definitions can define the data that is available in the API. We typically use what's called the schema definition or SDL to define these types. You can define your types programmatically depending on what GraphQL server implementation you're using. But SDL is nice because it's language agnostic. So it doesn't matter if we're building a GraphQL server in Java or JavaScript or Python, the SDL is gonna be shared because it's not specific to a certain programming language. We also will use directives. So here, you can see we're defining some types and we're defining fields that exist on these types. So we have movies, we have genres, we have actors. Movies have a title, it's a string, a year, that's an integer and so on. And then we're saying how these types are related to each other. So, movies were saying has a genres field that is an object array field of genres. When we get to using the Neo4j GraphQL library, and we're thinking of how do we represent the property graph model that we're looking at in Neo4j in GraphQL type definitions, we use directives, like annotations to the schema. So, here we've added this relationship directive that allows us to specify the type and direction in the property graph model, since in the property graph model, we have a direction and a named type for each relationship, but we'll cover that when we get there. Okay, so that's type definitions. Another important concept is this idea of GraphQL operations. So, like a query is really an operation where we're sending this document. What is the document? The document is the GraphQL query, essentially, or the operation. So, a query is either a query, which is going to be starting with a field on the query type or a mutation or a subscription. And we start at the root level, the entry point, I think, about it, for the API, which is gonna be a field on, in this case, the query type, and that field can optionally take arguments. So, here we are searching for movies where the title is A River Runs Through It. And then the next piece of our graphical query is the selection set, and so the selection set is this nested structure that I think is important for specifying two things. One is it's specifying this traversal through the data graph. So, we're starting from this movie, A River Runs Through It, and then we're traversing to actors, to genres, to directors, and then for the directors, we're also traversing out to see other movies that those directors directed. So who directed A River Runs Through It? What other movies did they direct? That's what this piece of the selection set is saying, it's in this sort of nested structure. Fields in our selection set can also take arguments optionally as well. So here, we're only grabbing the first two actors that were in this movie, and then we're only grabbing three movies that the directors of A River Runs Through It also directed. And then you can see, when our data comes back, the shape of the data, so in this case, it's a JSON document, exactly matches the shape of our query, so the client knows exactly what data they're getting back. So that is how we write queries and operations. How do we sort of implement the back end logic for a GraphQL server? Well, this is where resolver functions come in. So resolver functions, these are functions that actually have the logic for fetching data from the data layer. So querying the database, we can even query other APIs, so GraphQL is data layer agnostic, we can really build GraphQL APIs on top of any data layer. The example that we have here, this is looking at an application for conference. So we have sessions, sessions are in a room, sessions have a theme, we have recommended sessions. So if you like this session, here are other sessions you may be interested in, this kind of thing.

6. Addressing the N plus one query problem in GraphQL

Short description:

We can address the N plus one query problem in GraphQL by generating a single database query using the Neo4j GraphQL library. This eliminates the need for implementing resolvers and reduces the overhead of multiple round trips to the data layer. The library takes care of fetching data from the database, and the root-level query is generated automatically.

And we're using this sort of like ORM API here, assuming that we have that available for querying our database. So in this case, we would start off searching for a session with some query string and we go to the database and say find all the sessions by the search term and that would come back to our GraphQL server and then we would sort of iterate through that selection set and see, oh, well the user also asked for what room these sessions are in. So the room resolver would then go back to the database for each session that matched our search string, say here's the room that it's in and then do a similar thing for theme and for recommended. So you can see that we're doing these in sort of a nested fashion, right? So it's possible that for a GraphQL operation, we may make multiple round trips to our data layer. This is called the N plus one query problem, which is a common thing that comes up in GraphQL, which is that we have the possibility to be making multiple round trips to the data layer for a single GraphQL request. And this can be problematic for performance reasons, right? Like it's incurring some overhead to go to the database, to go to the data layer each time. It would be best if we could, in one operation, go to the database and say, here's all the data that I need for this GraphQL operation. And that comes back. So this N plus one query problem, this is something that comes up. There are different ways to address this. There's the data loader pattern, which allows us to do some batching and caching of objects. What we're going to do today with the Neo4j GraphQL library is see that we can actually generate a single database query. So in our case, this will be a single cipher query at the root level for any arbitrary GraphQL requests. So what that means is that we won't actually be implementing resolvers, instead, we're going to let the Neo4j GraphQL library take care of that for us, and that gives us a couple of advantages here. One is we don't have to write this kind of boilerplate syntax for fetching data from the database, instead, the library's gonna take care of that for us. And then we also don't have to worry about the N plus one query problem because this means that our database query is gonna be generated for us at the root level, which is quite nice.

7. Challenges and Considerations in GraphQL

Short description:

GraphQL provides benefits in terms of addressing over-fetching and under-fetching, allowing us to send only the necessary data to the client. However, it also presents challenges in error handling, caching, and query costing. These challenges require different approaches compared to REST APIs. It's important to be aware of these challenges and utilize the available tooling and best practices.

So you may have seen the benefits of using GraphQL. This idea of addressing over-fetching and under-fetching where we're not sending too much data over the network, we're getting exactly the data that the client needs to render a view. We don't have to make multiple requests like we may in a REST API for accessing different resources. We can just add more things to our selection set to give us the data that we need in our application. And then some of the challenges that come up, we talked about the N plus one query problem. But in my mind, I think the way to think of most of these challenges of GraphQL are that a lot of the practices that come from the REST world don't cleanly apply in the GraphQL world. So things like error handling is a bit different, right? We can have errors at different levels in our selection set. So we need to think of error handling a bit differently. Caching, similarly, GraphQL queries can be kind of arbitrary. So you can't just cache a certain endpoint or a certain URL like we may be able to in the REST world. And then also things like how do we handle query costing and rate limiting again, related to this idea of arbitrary complexity of GraphQL queries. So these are some of the challenges that come up there. There's tooling and best practices that address all of these, but I think these are just important things to be aware of that may come up.

8. Using GraphQL Playground

Short description:

We'll be using GraphQL Playground today to query and introspect GraphQL APIs. Take a few minutes to explore the docs tab, write some GraphQL queries, and get familiar with the Playground. Use control space for autocomplete suggestions and add fields to your queries. If you have any questions or issues, let us know in the chat.

So we're gonna use GraphQL Playground today. GraphQL Playground is a, I guess in browser tool for querying and introspecting GraphQL APIs. You may have seen Graphical or Apollo Studio has something called, is it called Explorer? I think that's built into Apollo Studio that in actually the Apollo, the linking out to Apollo Studio is now, I think the default with Apollo Server. These, these tools are similar. I like to use GraphQL Playground because we can just sort of host GraphQL Playground at our Graphical endpoints. So that's what we're going to use today. And we'll take a look at Playground in a minute. Actually right now, if we will.

So for this hands-on exercise piece, what I would like everyone to do is go to movies.near4j-graphql.com, and you will see GraphQL Playgrounds at that URL. And let's all take a few minutes to explore the docs tab, to see what the schema looks like, and then write some GraphQL queries. Just to get familiar with the way that, for example, our limit arguments work. So here we're looking for the first 10 movies, grabbing some information, then we're also filtering for directors. So I'm going to go to movies.neo4j-graphql.com. I'll drop a link to that, both in Zoom and in Discord. So you should see something like this. So in the right, we have the docs tab. So this allows us to inspect the API. We can see the query entry points, we can see the fields that are available on each type. And we can write some GraphQL queries. So note that it's quite nice because of this idea of introspection, we can do control space to get this autocomplete suggestions, so we can add fields. So here's, now we're adding the bio, the biography of each director, which is quite nice. So anyway, let's take a few minutes. Everyone can write some GraphQL queries and familiarize yourself with GraphQL Playground if you haven't seen it before, looking in the docs tab and using control space for autocompletes, add some fields to these queries and copy and paste these, I'll share the queries actually in discord. That's easy enough to do. There's the first query in discord and I'll drop the link for this other one in discord as well, so you can just copy and paste those. Great, so we'll pause here for just a couple minutes to give everyone a chance to get familiar with GraphQL Playground and this API and then we will pick up again. If you have any questions or issues, definitely just let us know in the chat. We'll pause for just a couple of minutes, so if you need a break, we will start up again in a couple of minutes.

9. Sorting Options and Building Our Own GraphQL API

Short description:

Let's take a look at our sorting options for movies. We can sort by title and either ascending or descending order. We can also sort by year. To build our own GraphQL API, we'll use Neo4j Aura. Sign into Aura, create a database, and choose the free tier. Copy the password provided. The Neo4j GraphQL library allows us to build graphical APIs backed by Neo4j. It supports GraphQL-first development and provides directives to configure the API and add custom logic. Let's get more hands-on with some code and build a GraphQL API.

Okay, so hopefully everyone had a chance to play around with this API, see what data is available. We haven't talked about how this API is implemented. Our friends says options for sorting, like by last name, descending or ascending. Yeah, so let's take a look at our sorting options here. So let's do movies, limit 10 and let's bring back, I don't know, title and year. So to see options, we have for things like sorting. There's a couple of ways to do this, right? So we could look in the Docs tab at the movies, query fields, and we can see the arguments are where. So this is gonna be for filtering. So we can filter based on fields or our options. Input takes a limit and an offset. So that's like basic pagination. And then sorting, we can sort by, so in this case we're sorting movies, right? So we're gonna sort by things like title and then either an ascending or descending order. So we could say something like, sort by title, descending. And we have, I guess we have some characters with accents and things like that. So they show up at the end of the alphabet. So ascending would give us, yeah, quote characters show up first. We can also do something like sort by year. Something like that. So 1902 is the oldest movie that we have. Cool. Anyone come up with any interesting queries that they wanna share in the chat? Otherwise we can move on. Okay, great. Let's move on here. Let's make this a bit bigger. There we go. Cool, so let's move on and talk about building our own GraphQL API. So we're gonna use Neo4j Aura for this, so everyone should follow these steps to spin up a Neo4j Aura instance if you haven't yet. Basically what we'll do, I'll walk through this, is we'll go to dev.neo4j.com slash neo4j Aura is the link, so I'll drop that in the chat and Zoom and Discord. So Aura is a managed cloud service or hosted Neo4j instances. There's a free tier, which was really nice, so we can spin up these Aura instances to work with Neo4j for like hobby projects or development, which is quite nice for what we're doing today. And then there's a professional tier and enterprise tier when ready to build a production application. So let's do the free tier. So we'll need to sign into Aura. So you can sign in with Google or create a user name and password. So I'll sign in with Google. And the first time you sign in, I think you have a bit more of a guided workflow, so you may see something a bit different that is prompting you to launch a database, but what you want to do is create a database and specifically, you want the AuraDB free instance, we don't wanna put in a credit card or pay for this or anything, but you can see if we choose professional, we have different ways we can scale the database and things like that, but for today we want the free tier. So the free tier databases, these are available for us to use, these stay around in perpetuity, I guess, they don't go away. There's just a limit on the size of the graph. So these instances have constrained resources, so we can't do massive amounts of data, but for hobby projects and what we're gonna do today, that's perfectly fine. So let's give it a name, we'll call this, how about GraphQL workshop, we choose different regions, whatever it recommends is fine, that works. And then we have an option for starting with a movie's dataset already loaded or a blank database. We're gonna add all the data we're working with GraphQL mutations today, so we'll just create our own data in a blank database, and I click create database, and the first thing that happens is it asks me, or it tells me rather my password. So I copied that password, I'm gonna save that somewhere else. We're going to come back to using the password in a moment. So definitely be sure to copy that and save that somewhere. And then you will see this message that we're spinning up your database, and it'll take a few minutes. So let's pause again for a couple of minutes and give everyone a chance to sign into Aura and provision and start a free tier instance. Be sure to copy your password and save that somewhere, because we will need that later. And then you'll see in the console application that your database is starting up, and then you should be good to start moving on and building our GraphQL API. So we'll stop here for just a couple of minutes to give everyone a chance to go through that. If you get stuck on anything or have any issues, definitely let us know in the chat, either on Zoom or Discord, but we'll start again in a couple of minutes. Thank you. Okay, so has everyone been able to sign into Aura and create a database? Or at least start the process of spinning it up. He says yes. Okay, great. We'll definitely let us know in the chat if if you got stuck on anything, but let's move on. We'll talk a little bit about the new graphicual library what what this does for us and then we will get more hands-on with some code and build a graphically. Okay. So first of all, the new graphicual library, this is a node js JavaScript library that makes it easy. To build graphical APIs backed by Neo4j. So like at a fundamental level, we're talking about building this API layer that sits between the client and the database where we may have things like our authorization, we may have some custom logic, we don't want to just expose our database to the world, right? There, there's still this need for the API layer. So we're not talking about just sending GraphQL directly to the database. So that's at a fundamental level, what we're doing. At a more specific level, the goals of the Neo4j GraphQL library are to support this idea of GraphQL-first development where we're using our GraphQL type definitions to drive model, and then also the schema for our API. So we're not maintaining two separate schemas, one for the database, one for the API. We can, of course, configure the API so that we're not simply just exposing our database. We do this through GraphQL schema directives. We talked about this relationship directive, which we'll see in a minute, but there are few directives we can use to do things like configure what we're exposing through our GraphQL API. We can add custom logic with Cypher. We can add authorization rules and so on, all through this idea of directives.

10. Neo4j GraphQL Library and Custom Logic

Short description:

The Neo4j GraphQL library generates a GraphQL API with CRUD operations for each defined type. It handles generating the database query and optimizing performance, solving the n++ query problem. Graph databases like Neo4j excel at traversing relationships, thanks to index-free adjacency. The library also allows us to add custom logic using Cypher statements and schema directives. We can expose any functionality we have in Cypher to our GraphQL API. To get started, we install the Neo4j GraphQL library and its dependencies, such as the GraphQLJS reference implementation and the Neo4j driver. We can use any JavaScript graphical server implementation, and Apollo server is a popular choice. Here's a minimal example of using the Neo4j GraphQL library with Apollo server.

So another thing that the Neo4j GraphQL library does for us is basically takes our GraphQL and then generates a GraphQL API that has CRUD operations, so create, read, update, delete operations for each type that we have defined. So in GraphQL parlance, these are things like generating the query and mutation types. for the API, adding arguments for things like ordering and pagination, complex filtering, also adding support for working with things like the date time, like the temporal types and the spatial types that are available in the database. And then also, some things for aggregations and more complex operations. All those are generated for us. We don't have to add those explicitly to our schema.

Then at query time, for any arbitrary GraphQL operation that we send, a single database query is generated for us by the Neo4j GraphQL Library. So that means we don't have to write these resolver functions. The library takes care of generating the database for us. We don't really need to think about that. Think about, in this case, writing Cypher queries to build our GraphQL API. We don't need to do that. We only need to think about Cypher when we get to thinking about things like adding custom logic. This is really nice for developer productivity. We can get a GraphQL API up and running back by a database basically just by writing some type definitions. And then the performance aspect. This solves the n++ query problem for us by generating a database query and sending it to the database to figure out how to optimize. And Graph databases like Neo4j are really good at traversing the data graph. That's what Graph databases are optimized for. So, oftentimes, in GraphQL, we end up creating these queries that have a very nested structure, a very nested selection set. And so Graph databases are very good at traversing that graph. In a database implementation terms, what's going on there, there's something called index-free adjacency, which means that in Neo4j, in the database, we can traverse from one node to any other node that node is connected to, so traversing along relationships. We can do that without using an index. So in a relational database, to do the equivalent of that, which would be a join, we're using an index to see where two tables overlap, so a set operation. And that has to use an index, which means that that slows down as the size of those tables grows. But in Neo4j, the traversal, so the equivalent of a join, we're basically just chasing pointers, going to an offset, which is something that computers are very fast at, so it's more of a constant-time operation that's only dependent on the number of relationships that we're traversing, not on the overall size of the data. So as we add more data to the graph, our traversals from one node to another stay the same performance for those. So that's under the hood what's going on, and that's why graph databases are really good for traversing relationships.

Okay, so that's one of the goals of the Neo4j GraphQL library. The other is to expose custom logic through Cypher. So we said that the library generates CRUD operations based on the type definitions. We don't have to write any Cypher, any data-fetching logic. We just have to basically write our type definitions. That's great for basic CRUD operations. But what about when we have custom logic? Well, and for that, we can use Cypher statements in our GraphQL type definitions using the Cypher schema directives. So schema directives, these are like annotations in our GraphQL API, in our type definitions that are basically indicating that some custom logic should occur. So it's saying that there's some custom logic that needs to happen server side. It allows us to basically extend things in GraphQL. So this Cypher schema directive, this is like an annotation that we would add to our type definitions. It takes a single argument, which is a Cypher statement. So in this example, we're adding a recommended field, I think on a on the business type. So this is from an application that has businesses and user reviews of businesses. Think of something like I'm searching for restaurants and I want recommended restaurants. So I know a restaurant that I like. Here are other businesses, other restaurants that you may like as well. So the Cypher statement here is finding users who have reviewed the business that we're currently resolving and then looking at other businesses that those users have reviewed and using the number of overlaps as as a score for the recommendation. So this is a what's called a collaborative filtering recommendation query where we're using information from other users in the network to generate personalized recommendations. This is a a fairly basic example of collaborative filtering, but I think the idea applies for more advanced cases. But this this kind of traversal is very expressible in Cypher and graph databases. So now we're able to add this recommended field to our business type to the client of our API. They don't know that this is a custom field with this logic defined by Cypher. They just see a recommended field that is giving them an object array of business objects. So, I think this is my favorite feature of the Neo4j graphical library. This is super powerful because what this means is that we can use any functionality that we have in Cypher. We can expose that into our graphical API, which is super powerful. You'll notice, I guess, one thing that is interesting, which we have this keyword here. This is referring to the currently resolved business object in this case. So that's kind of like a special variable that gets injected into the Cypher statement.

Let's look at how we would get started with Neo4j GraphQL library. We don't follow along with this. We're gonna jump into a code sandbox example in a minute, but I want to just go through the concepts. So we will install Neo4j GraphQL library and its peer dependencies, which is the graph QLJS reference implementation, and the Neo4j driver. This is the Neo4j JavaScript drivers as we're building a node.js API. These database drivers, they allow us to create a connection to the database, whether it's running locally or running in the cloud somewhere, all we're going to do with it is just create that connection and then pass that driver off to the Neo4j GraphQL library. Then in this case, we're using Apollo server, which is quite nice and simple for creating graphical servers. But we could use any graphical server, any JavaScript graphical server implementation, with the Neo4j GraphQL library. Here's kind of the minimal, viable snippet. So let's walk through what's going on here. So the first thing we do is import our dependencies. So GraphQL, the driver and Apollo server.

11. Defining Type Definitions and Data Model

Short description:

We define tight definitions for movies and genres using the relationship schema directive. Then, we create a connection to our database using the Neo4j JavaScript driver and an instance of Neo4j GraphQL class. This gives us an executable schema object that we hand off to Apollo server. In CodeSandbox, we'll be building a GraphQL API for an online bookstore. We start with graph data modeling, identifying entities, properties, and relationships. We then define the data model and use the Arrows tool to diagram it. The data model includes books, authors, orders, customers, and reviews.

Then we define some tight definitions. This is just looking at movies and genres. And notice here that we're using this, relationship schema directive. So we said that in the property graph model, every relationship has a direction and a named type. GraphQL doesn't have that same concept for relationship fields. So we need to be able to encode that data because we're driving the database model from these type definitions. So we need to be able to specify that data to the type definition. So we need to be able to specify that data somewhere. So we do that with this relationship schema directive to specify the type and the direction.

Then we create a connection to our database using the Neo4j JavaScript driver. There's a connection URI, which this is the default for if we're running locally with like Neo4j desktop or Docker or something like that. And then there's a few different ways to authenticate we're just using a username and password. Then we create an instance of Neo4j GraphQL class passing off our type definitions and the driver. And then that gives us a executable schema object that we can then hand off to Apollo server which is then going to serve our GraphQL API. So note that we're not writing any resolvers we don't have to write any data fetching logic. Basically all we're doing is writing type definitions handing that off to the Neo4j GraphQL library get back an executable schema object and pass that off to Apollo server. And if we started this, then we would have we would have a GraphQL endpoint running locally. So that's the basic idea of what we're doing. You can see that most of the interesting aspect here is going to be in writing our type definitions, configuring those the schema directives, handing that off to the Neo4j GraphQL library.

Okay, that's it. Great. Well, let's get hands-on with an example in CodeSandbox. What we're going to do for the rest of the workshops, we've got what an hour and 45 minutes left. So what we're gonna do for the rest of the workshop the GraphQL API for an online bookstore. So the first thing that we would typically go through this graph data modeling process. Now, someone has already done this for us in this case, we're gonna be starting off with existing schema. But I think it's helpful to talk about how we get to the types, how we get to the data model that we ended up with. And I think of this graph data modeling process is kind of this iterative process where the first thing we do is identify what are the entities in our business requirements, essentially. So we start off with some business requirements that are like, I need to as a user, search for books by like a search string or search for books by subject. As a user, I want to be able to add books to an order. As a user, I want to be able to submit a review of a book, these sorts of things. Our business requirements, we go through identify the entities, think about what are the properties that we're storing. So books have an ISBN, which is basically like an ID field. They have a title. How are these entities connected? And so how do those become relationships? And then sort of draw out the graph model. And then the next part is to think of the questions that we have from our business requirements. So maybe I need to view all of the books in an order for a specific customer. And I think, well, can I traverse the graph to answer that question? Well, can I go from a customer to an order, from the order node I can traverse out to the books contained in the order? So yes, I can answer that question by traversing the graph. This way, I go through each of those for my business requirements. And then if I can answer all of the questions that I want to answer, then I'm done. My graph model is ready to go. If not, then I may need to iterate on that a bit. So I think of this as a very iterative process. So this is the data model that we are going to use today. So we have books. Books have a title, price, and description. Books are about a subject. We have authors. There are authors of books. We have orders that contain books and ship to an address. Customers can place an order and customers can also write reviews that are connected to a book. So this data model, by the way, we use this tool called Arrows. So Arrows.app. I'll drop a link to in the chat and Discord. We use this tool Arrows to, basically diagram our data model. So fundamentally Arrows is a graph diagramming tool, but it's very convenient. It allows us to express the property graph model. So for example, here's, this isn't exactly what we're working with. It's from a similar project, but it's very similar. So we can drag out nodes, so maybe user wrote a review. And then, well, review needs to be connected to a book. So we can update our model this way. And then we can check this in to version control. We can export say like the JSON for this and check that into version control, which is quite nice. We can also export GraphQL type definitions.

12. Exporting Data Model as GraphQL Type Definitions

Short description:

We can export our data model from Arrows as GraphQL type definitions, making it easy to generate a GraphQL API using the Neo4j GraphQL library. This allows us to quickly go from diagramming our data model to having a fully functional GraphQL API.

I don't know why that looks weird. Label book. We can also export GraphQL type definitions. Although it doesn't think I have a label on book for some reason it's there. Let's delete our... Oh, I had a duplicate. Nice. Book. So we go through this data modeling process in Arrows and we can export these as, Oh, I need at least one property. So book, let's give it a title. There we go. So now, we're generating GraphQL type definitions that we can just copy and paste and hand those off to the Neo4j GraphQL library from just this diagram. So this is really nice. It allows us to quickly go from diagramming our data model to generating GraphQL type definitions, basically copy and paste into some template code. And we have a GraphQL API, which is super powerful.

13. Setting up Code Sandbox Environment

Short description:

To set up our code sandbox environment, we'll start with a specific code sandbox link provided in the chat. After forking the code sandbox and signing in, we'll configure the environment to connect to our Neo4j Aura instance. The code editor will resemble the getting started example, with additional packages imported. We'll replace the environment variables with our Aura instance connection credentials. Then, we'll instantiate the Neo4j.graphql class and create a driver instance. The executable schema object is handed off to Apollo server, and our GraphQL API is started. We can test the API by running queries in the GraphQL Playground. Let's take a moment to open the code sandbox link, fork it, update the.env file with our Aura connection credentials, and run a simple query to ensure everything is set up correctly.

Okay, so the next thing we want to do is set up our code sandbox environment. So we're going to start with this specific code sandbox. So there's three of these for the remaining modules. So we'll have a starting point for each one of these modules. And what we'll have to do is everyone will open the code sandbox and then fork it. So you'll need to sign in to code sandbox if you're not already signed in, but it's free to sign in with something like, I think you can use GitHub or email. And then that makes the code sandbox private to you. So only you can edit it. And what we're going to do is configure our initial code sandbox environment to point to our Neo4j Aura instance. So we're gonna open the code sandbox link here, which I will, put in the chat. Dev.neo4j.com slash graphql-sb1 sandbox1. Here's the part1. And you'll see something like this. And the first thing that we want to do is click this fork button. So you can see here, if you look in this long URL, this is just pulling in some code from GitHub. So all the code for the examples we'll look at is on GitHub. But we're going to fork this, and then that's the point we need to sign in, it looks like I'm already signed in. So when you click fork, it'll ask you to sign in. And then give you a new code sandbox, which only you can edit. And we have code editor, and then we have the web app, and in this case, GraphQL Playground running on the right here, and the terminal. So we're just gonna edit all of our code in code sandbox in the browser here. But we have a basic starting template. Let's look at what's going on here. So this will be our code editor. What's going on here? So this will be in structure, pretty similar to the getting started example that we looked at, with a couple of things added. So we're pulling in Neo4j GraphQL library, Apollo server and the Neo4j JavaScript driver. And then a few utilities. We are loading some environment variables from this file. So these, yours maybe blank, or you may have old values here. We're gonna replace these with the values for our aura instance. Let's go ahead and do that. So I'm gonna go back to the aura console, and I'm gonna grab the connection URI. Paste that here. And then my password was generated, when I started the instance and we said we needed to save that somewhere. So we'll paste that in, and then when I save this, so I'll go file, save. I save that, it will restart my application because we're using node bond, and it will now be connected to my Neo4j aura instance, which I started up in the previous module. Okay, so we're reading some environment variables. Then we're reading the schema.graphql file into our type dev. So schema.graphql, so if we look at this, this matches the data model that we were looking at a moment ago with customers and orders and books and reviews. Then we hand off those type definitions when we instantiate the Neo4j.graphql class, we create a driver, Neo4j.driver instance, and this is where we're reading those environment variables. So the values that we're setting here in this.env file are being pulled in here as environment variables to specify our connection to Neo4j. Then we hand off that executable schema object to Apollo server, start our GraphQL API, which if we look in the right side of the screen, so you can, if you need more screen real estate, you can copy this URL and open that in a new tab. So this will be a private, this will be a different URL for your code sandbox. But that can be nice. I'm gonna do everything from here though, because I want to see the terminal, the console results log here. And so if everything is working, if everything is wired up, we should be able to, so for example, click on the docs tab here and see our entry points. So we have query fields for orders, orders count, this is like an aggregation, customers addresses. And then we have all of these mutation operations for creating, updating and deleting orders and books and such. So if everything is wired up correctly, we should be able to run a query. How about, give me all books and title of each book. And so I run that, of course I get back a empty array because I don't have any data in the database. But I can see that I didn't get an error, so I actually was able to query the database. And if I look in the console here, I can see a few things logged. So it's telling me that okay, there's an incoming GraphQL request, here's the query, no variables, there's no JSON web token. We will definitely use JSON web tokens when we get into the auth section. And then here is the generated cypher query. So the Neo4j GraphQL library has taken this GraphQL request and generated this cypher query and sent that to the database. And of course, nothing comes back because we have no books, but this is neat because I can add other fields. So that's also I don't know, say, bring back the price of the book, I can see now that the cypher query includes the price property as well. And so, as I add more complex operations, do I have what else do I have for book, do I have any reviews? I can search for reviews for all the books. And of course, I'm still getting an empty array, but the generated cypher query now includes this graph pattern for finding any reviews connected to the book. So the cipher query is generated specific to the GraphQL operation, which is quite nice, means we didn't have to write any data fetching logic. Okay, so we're gonna use this as kind of a skeleton starting point for adding some more things to our API. So let's pause here for a couple of moments, give everyone a chance to open the code sandbox link. So that's this link here, dev.newfjetter.com slash graphql-sb1, which should be in the chat both on Zoom and Discord. And then fork the code sandbox and update the.env file with your connection credentials for your Aura instance. And then that will restart your GraphQL API application in code sandbox and write a simple query just this books title one is good. And you should get back an empty array. You shouldn't see any errors. So you see an error, we knew that something went wrong, but that's the basic setup.

14. Adding Data with GraphQL Mutations

Short description:

Let's pause for a few minutes to ensure everyone is set up and connected to their Neo4j Aura instance. We'll then discuss the type definitions and directives used in our GraphQL schema. After that, we'll explore how to add data to our database using GraphQL mutations. Let's switch to Code Sandbox to see the generated cipher and start by creating a single book with a randomly generated ISBN number. We'll use the 'create books' mutation and the 'book create input' type. For example, let's create a book titled 'Graph Algorithms' with the ISBN number 3748.

Let's pause for a few minutes. You're gonna chance to go through that. If you get any errors or have any issues, definitely let us know in the chat and we will get that figured out because we do wanna be connected to our Neo4j Aura instance going forward because next we're going to see how to add some data with GraphQL mutations. And then we'll need to add some things to our type definitions that we left out. So we'll see how to add some types and fields in our GraphQL API.

Okay. How is everyone doing? Does anyone have their code sandbox set up, working, connected to their Aura instance? Is anyone getting some errors? Okay. Not then I think we can move on. Okay, well I don't see anyone complaining in the chat that they had errors. So, I'm gonna assume that we all got our code sandbox up and running and we're connected to our Aura instance and we are ready to move on. Cool. So this is, yeah, so this is the steps that we want to go through. If we didn't provision our Aura Instance previously, we definitely want to grab the connection string from the Aura Console here. So this is the connection string for our database. And then when we first spin up or first provision the Aura instance gives us the password, which we're going to take both of those, put those in this dotenv file in our code Sandbox to get our GraphQL API connected to our Aura instance. Cool, so hopefully that's where everyone was able to get to. Let's talk a bit about the type definitions that we're working with. So if you look at the schema.graphql file, in our code Sandbox, so that's this file here. You can see that these type definitions correspond to the graph data model that we came up with earlier when we went through this graph data modeling process of thinking about what are the entities? How are they connected? This sort of thing. There's a couple of interesting things that I wanna point out. One is the relationship GraphQL schema directive, which we mentioned before. We used to specify the direction and the type of the relationship. But you'll also see some other directives that we're using. So the timestamp directive, which we have on the order playlist at field. So playlist at is of type date time. So first of all, we're using date time. We also are using this point type. These are added by the Neo4j GraphQL library to expose of temporal and spatial types that are available in the database. So point, date time, local date time, date, these kinds of things. Timestamp though is a directive that we can use to indicate that we want this value to be automatically generated for us in the server. So when we create an order, this is saying set the place that property to be the current date time. We don't want the client to be responsible for that. We don't want the client to say, yes, this is the current time that can be. A pain for the client to do and also be a security vulnerabilities. We want just to set that on the server. The ID directive is similar that's saying, well, this is the field we want to use to identify a uniqueness, but also we want a UUID to be generated for us automatically when this order object is created. So generate a random unique ID, set that as the order ID value. The client doesn't need to be responsible for that. So these are some examples of the way that we're using directives to configure the schema that we're creating. There are a few more directives. If we look in the documentation, I'll drop a link to this in the chat also. This is the documentation page for the Neo4j GraphQL library, which is helpful to have up as we're working through this. But you can see here there's quite a few directives that we use for configuring our schema. So for example, the auth directive, which we'll be using quite a bit in a moment, allows us to add authorization rules to our schema.

Okay, so that's directives. Let's take a look at adding some data to our database using GraphQL mutations. I'm gonna switch to Code Sandbox here. And hopefully that's big enough to see. I want to do everything in Code Sandbox here so that we can see the generated cipher. I think that is useful to sort of reason about. Okay, so what do we wanna do? We want to create some data in our database using GraphQL mutation. So first of all, if we look at the Docs tab, so far the examples we've been using have all been query operations, but we need to start with creating some data. So we can see we have create, delete, update, mutation generated for each type that we've defined. Here's the one for orders, orders takes, create orders takes an input of order create input type. And we can see it takes things like the shipping costs, the customer books, which can be used to connect in this case to existing books or to create new books. So you can see actually some fairly sophisticated things we can do here. If we think about these different operations that we have available in this input object. But let's start simple. Let's start with creating a single book. So we're going to look at the mutation. so mutations create books. So this book create input is what we're going to be working with. So we'll say mutation create books, takes an input object. Actually, this is an array of input objects. We could create multiple books in one operation, but we'll just do one. So book is going to have an ISBN number. We'll just make this up. So ISBN, this is like the, I don't know, like the ID of the book in some international format. Let's create our book graph algorithms. That is available for 3748.

15. Creating a Book and Review in Neo4j

Short description:

We create a book called graph algorithms and verify it in Neo4j browser. Then, we create a review for the book, connecting it to the existing book using filtering. The review node has properties such as rating, text, and a created at timestamp. The server sets the created at value using the timestamp GraphQL schema directive.

It has a description. This is the sample for examples in Neo4j and Apache Spark. And then for our selection sets, let's bring back book, title, ISBN, price. Right, just for the fields that we specify. And then we also have this info object, which we'll use to tell us the number of nodes that were created, if any.

Okay great, so let's run this. And says, yeah, we have now a book called graph algorithms. We created one node. If we scroll down, in our console we can see the generated Cypher query, which is neat. So it's doing a create statement, setting some property values. Neat, now we could open this up in Neo4j browser to verify that we actually did create some data. Actually, let's go ahead and do that. If I go back to Aura, I can go to open with and I can either open Neo4j browser, which we saw before, or Neo4j Bloom, Bloom is like a no code visual exploration tool, so Bloom is nice if I want to visually explore graph data without writing any Cypher. But let's do browser for now. And then I will need... We'll close this so it starts with a helpful guide. We'll close that. And then I need to put in my password, which I saved over here somewhere. Great. So I'm in and I can write a Cypher query that says, match on everything, return everything. So this says, find all nodes. Previously, we had like a colon article or something in here that was the label. This a refers to the variable that we can use to refer to any nodes that we match on this pattern later on. So this just says, find all nodes in the database and return them. And it says, yep, you have one book, you're the properties of the book. So that's what we created here. So we've created a single node, that's fine, but we have a much more rich data model to work with. So let's look at creating a review. So let's run another mutation operation. So we'll say mutation. And this is going to be create reviews, which is going to take the input object. Oh, my container has hibernated. Let's restart it. Restarting the browser, do I need to restart this browser? No. Okay. So I just need to restart our container. Yeah. So we're writing this create reviews input. So review, takes a rating. Let's give this book five stars. This is really the best overview of graph data science. Really is. It's a great book. So that's the review, which will create the review node. But we need to connect this review node to the book, no that we created earlier. So we have a book field. And we have two options here. We can do a create operation. So we can create a new book or we can connect to an existing book. So this is a review for the graph algorithms book. So we're going to connect to an existing book. And then we have a where argument that we can use to specify some filtering. So we should probably use the ISBN here since that's like the canonical ID that refers to the book but I can't remember what I typed. I just made something up. So let's just use title, but no it's interesting all of the options that we have here for filtering. We can basically do any filtering on any of these fields of our book type. But what we want to do is filter for where the title is graph algorithms. So this is going to create a review node, set the text and the rating, and then create a relationship to the existing book. And then in our selection set, we'll bring back any reviews that we created. How about text, rating, and then also we want to make sure that it goes for the right book. And then we also have this info object, which we can use to return the number of relationships created. So we'll run this. We get back some properties from our review. It says, yep, we're connected to the graph algorithms book. If we take a look now in Neo4j browser, so we can either write a new cipher query, we just double-click on this to traverse out. Yep, here's now a review node that is connected to the graph algorithms book. And it has a rating text and a created at timestamp. And remember we didn't have to specify that created at value in our GraphQL mutation. This was set by the server because we use that timestamp GraphQL schema directive. That value is set for us.

16. Nested Mutation Operations

Short description:

We can create complex subgraphs using nested create connect operations in GraphQL mutations. This allows us to create multiple nodes and relationships in a single operation. For example, we can create a new customer, connect reviews to the customer, create orders for the customer, and add books to the orders. The relationships between the nodes are defined in the GraphQL schema, and we can visualize the created structure in the Neo4j browser.

Okay, cool. We can also create more complex structures. So these mutations have these nested create connect operations. So we can actually create more complex sub graphs. Let's try running this one. So instead of typing this one out, I'm just going to copy this. What am I missing? Oh, I'm missing the selection set. And then this piece. There we go. So this is actually a fairly complex operation. So what are we doing? So now we're starting from create customers. So we're creating a new customer, and then for the reviews for this customer, we're going to connect. We're gonna create a new customer node and connect relationships to reviews this customer has written. In this case, where the text says best overview of graph data science, which should match, this node. Again, we should be using an ID or something for the review, but this works. Then we're going to create orders for the customer, and we're going to add the graph algorithms book to that order for the ship to, which this is the relationship to the address. So if we look at our type definitions for order, we can see that order has a books, has a customer, and it has a shipped to relationship field, which is connected to a single address. And the address node has an address and a location, which is a point, which we're specifying here. And the input for creating our address node, which will then be connected to the order, which is connected to the customer. So you can see all of this structure that we're creating in a single GraphQL operation. So let's run this. And again, we could look at the generated Cypher query here. If we wanted to. It ends up being fairly complex again, because we're creating several nodes and relationships. And we can find this in the browser. So now in U of J browser, we can traverse out. See, yep. Here's this user who wrote a review of this book. They also placed this order. Note that the order has a auto-generated order ID. This is because we use the ID schema directive to say, hey, we want to auto-generate this. And then we have the place that timestamp, which is also auto-generated for us. And we can see we are shipping to this address. And the order contains this book. Cool. So that is this concept of nested mutation operations where we can actually create lots of things in a single GraphQL mutation. We can create nodes, we can create relationships, and so on.

17. Querying Data with Neo4j GraphQL

Short description:

To query the data we've created, we can use the generated query fields, such as 'books' and 'orders'. The Neo4j GraphQL library automatically adds features like sorting, pagination, and filtering to our API. We can sort by fields in ascending or descending order, and paginate using offset or cursor-based methods. Filtering is also available, with different operators for different field types. For example, we can search for books with a price less than $20. The 'where' argument can be used at the root query field or nested within the selection set. It's important to note that the filter is applied at the level where the 'where' argument is used. Let's now take a closer look at these querying features and explore how we can retrieve the data we need from our GraphQL API.

Okay, great. So if you were following along with that, we're going to clear out our database. There's a mutation here in this slide, and I'll paste this. Actually let me do this now. What we want to do is delete all the data in our database. So if you didn't run any of these mutations, you don't need to worry about deleting the data, but then we're going to run this mutation. which I don't have nitro on Discord so I can't paste, but I think I can send this as a snippet. Well I will do this. I guess I'll do this in two. Let me send one for the selection set. Ah, there we go. Okay, so if you have the slides open, this is slide 50 which is this mutation operation. I also pasted it in Discord, but what we wanna do first is open up Neo4j browser. So, in the Aura console, you should see your Neo4j instance listed here. Go to open with Neo4j browser, it'll be prompted for your password here, and it looks like this. And then we're going to run this cypher query, so match, oh, it's in Discord too, match a detach delete a. Make sure you're in the right Neo4j instance, because this will delete all data in the database. And once you do that, then we want to run this big long mutation, which is going to create some sample data for us to work through the next section. So I'm going to go to Neo4j Browser, let's say match a, detach delete. The reason I say detach, so this is matching on all nodes. And then I could say delete a, and that would delete the nodes, but I can't have relationships with the nodes that are being deleted. Relationships without the node, so the detach is just acknowledging that I also want to delete all of the relationships connected to all the nodes that I'm deleting as well. Okay, so I've deleted five nodes. So now I don't have any data in my database, and I'm going to copy this mutation, and go into GraphQL playground here, paste this and run it. And we've created three books and some customers, we can look at this in the database, this is what we created, three books, some orders, some customers, some reviews, some addresses and so on, so basically some sample data that we want to work with, so we'll pause here and give everyone a couple of minutes to clear out their Neo4j instance and then copy and paste this mutation and verify that you have created some data in Neo4j, so this will be the sample data that we'll use to take a look at some of the features that are added for querying with Neo4j GraphQL library and then also we will then take a look next at adding custom logic. Before we get to custom logic the next exercise will be on adding some missing types, so if you're running ahead of us a bit you can take a look at the next exercise if you want to see how we would update the GraphQL type definitions and then we will then begin to add authors and subjects which we did not include in our initial schema but let's pause here for let's to the top of the hour, two minutes if you need to take a break or want to make sure that you've got this mutation working so if you have any errors or have any issues definitely let us know in the chat otherwise we will get going in two minutes. All right. Okay so everyone able to run that mutation to create data in the database? Give a shout in the chat if you weren't if you had any issues with that otherwise we will move on to take a look at how we can query this data that we've now created. Okay let's look at how we query this data. So we looked at the mutations that are generated for us. We saw this concept of these nested mutation operations where we can create nodes, connect to existing nodes, create relationships. Now let's take a look at the query side of this. So we've defined our type definitions. We didn't define explicitly the things like the ordering and pagination and filtering, all these things. We didn't define those ourselves in our type definitions. That was added to the API for us by the Neo4j GraphQL library. So let's take a look at some features of the things that were generated for us that enable us to query this data. So by default, every type that we've defined in our GraphQL type definitions have a pluralized top level query field. So type book becomes books, order becomes orders, just to refer, just indicate that that is a object array field. So each one of these then becomes an entry, a query entry point to our API. One way to think of this is the query field, the entry point to the API, that becomes the starting point for a traversal through the data graph. And of course, as we add more fields to our selection sets, the database query that is generated behind the scenes takes that into account to resolve all the data for us that we've requested. For sorting and pagination, in the options input, or in the options argument, we have input options for sorting by fields of the type in ascending and descending order. We can do offset-based pagination using limits and offset. So give me the first 10, skip 10 for the second page, skip 20 to the next page and so on. And this is where the count queries. So we saw there's a books entry points, there's also a books count, which can tell us the total number of books. So we can use that to calculate our slices for offset-based pagination. So we know how many total books there are, we know we're doing them in slices of 10, so we know how many total pages we're gonna have. We can also do cursor-based pagination with the Neo4j GraphQL library using relay connection types. So here, for example, we are searching for a specific order, and then there's a books relationship field. There's also a books connection field that's available. The books connection will give us the relay spec connection types, which give us things like page info. And also for example, to get a cursor to allow us to do cursor-based pagination for iterating through these connections. We then use this edges and node relay style syntax for grabbing the actual nodes in this case, for grabbing the actual books that are connected to this order. So this query is saying, find a specific order and then use cursor-based pagination to paginate through all of the books in the order. We don't know if we have an order that has a lot of books, this may be useful. So different options for pagination. For filtering, there's a where argument that is included. This is both at the query field and also nested within the selection set. We can also apply this filtering. The filters that are available for each field will depend on the type of the field. So for string fields, we have a common string comparison operators. So things like starts with, contains, ends with this sort of thing for numeric fields. You have greater than, less than, those sorts of things. So here we're searching for all books that have a price less than 20, I guess this would be $20. So I mentioned that the where arguments can be used at the root query field or also nested in the selection set. It's important to note that the filter is applied at the level where the where argument is used. So for example, in this example, we're searching for books where the price is less than 20, and then for those books, the price is less than 20. We're grabbing all reviews that were created after a certain date.

18. Filtering Based on Geo-Distance and Relationships

Short description:

We can filter based on geo-distance, searching for addresses within a specific radius. The filter is applied at the level where we use the filter argument. To apply a filter at a higher level, we can use filtering through relationships. By nesting the filter in the where argument, we can find orders with a ship-to location within a certain distance from a specific point.

So we're filtering the books and then we're filtering the reviews. We're not sort of saying only show me books that have a review created after this date. This filter for the date is being applied to the reviews of the already filtered books, if that makes sense. So the filter is applied at the level in the selection set where I use it. We can filter based on geo-distance. So on our address nodes, we have a location property that is a point. So latitude and longitude point. For any point fields, there's a filter generated that allows us to search by radius distance within points. So here, we're saying, find all addresses that are within one kilometer of this point. This is somewhere in the area in California. And we get an address in San Mateo, which is the only one that's within a kilometer of wherever this point is. So we just said, on the previous slide, that the filters can filter based on geo-distance. It can be nested, but they're applied at the level where we use the filter argument where we use the where argument essentially. But what if we want the filter to be applied sort of higher up. So in this case, we want to filter orders. So we want the filter to be applied at the root level. But what we want to filter on, is orders that have an address node where the location of the address node is within one kilometer of this point. So to do that, we use filtering through our relationships. So we create kind of a nested structure in our where argument. So here we're saying, find orders where the ship to location distance is less than one kilometer from this point. So you can see we are nesting the ship to filter in this where argument. And we end up with only one order that was sent to an address within one kilometer of this point.

19. Updating GraphQL Schema and Running Mutations

Short description:

Let's update our GraphQL schema by adding the author and subject types. We'll then run GraphQL mutations to add authors and subjects based on the provided table. If you need help, the solutions are available in the readme file of another code sandbox. Let's take a five-minute break and reconvene after to review the solutions.

Okay, great. So that is a look at some of the generated query semantics that are generated as part of the Neo4j GraphQL library. What we want to do next is a hands-on exercise to update our GraphQL schema. So we left a few things out. We need to update the schema.graphql files. We need to update our type definitions to include author type and to include subject type. And then once we've added those types in the schema, so also think of the relationships that we need to add, then we want to run some GraphQL mutations that are going to add the authors and the subjects to our database based on the table below. So we have three books. We have the authors here of the books and we have the subjects for each book as well. So let's pause maybe five minutes or so, let's pick up again at 16 after the hour. So in the code sandbox that we have open, update schema.graphql file to add the author and subject type. Also think of the relationship directives that you'll want to use to connect author and subject to books and then see if you can write the GraphQL mutations to add authors and subjects based on the table here to the graph. If you get stuck the solutions are linked in the readme file of this other code sandbox. But let's pause for five minutes and then we'll come back and take a look at the solutions. If you get stuck, if you have any issues or questions, feel free to ask in the chat.

20. Adding Custom Logic with Neo4j GraphQL

Short description:

In this section, we added the author and subject types to our schema. We defined the fields for each type and established the relationships between authors, books, and subjects. We also created mutations to connect authors to existing books based on their titles. The schema now includes additional custom logic using Cypher directives and a new weather type. We've implemented a resolver in the Index.JS file. To continue with the workshop, we cleared our database and set up a new code sandbox. The updated schema includes authors, subjects, and Cypher directive fields. We ran a mutation to create data based on the full schema, including authors, books, customers, and orders. Now, let's dive into the topic of custom logic and explore the capabilities provided by the Neo4j GraphQL library.

Okay. Okay. So that was five minutes, I think. Did anyone get through this? Was anyone able to update the GraphQL type definitions to include author and subject and then craft the mutations to add those to the Graph? Anyone able to get that done? Okay, well let's take a look at the solution. So we have got about 40 minutes left and we have a section on custom logic in the authorization section, which I want to make sure we cover. So maybe let's take a look at the solutions for this fairly quickly and then move on here. So my container has been hibernated, I'll refresh that. So this happens sometimes with Code Sandbox that it will go into hibernation, we need to give it a restart. I think overall Code Sandbox has been pretty good for these sorts of workshops. I think it's... there's a trade off right between these using online tools like this or getting your local development environment set up, which can sometimes be a challenge in these sort of online workshops but I like Code Sandbox, so okay we said we need two types, so we're gonna add an author. Author has I think just like a name and subject, which also probably just has a name, we'll make these fields required or non-nullable, that's what this exclamation point means, that to create an author node, it needs to have a name, to create a subject node, it needs to have a name and then we need a relationship field, so an author, an author can have written one or more books, so we'll make that a object array field and then we wanna use our relationship directive, so the author, let's say author wrote a book, and then the direction, so we're going from the author to the book, author, wrote, book, so in this case, from the author, the direction is going to be out, and then similar for subject, subject will also have, call that field books, And the relationship type, which we call this one, a book is about a subject, and so in this case, we're gonna go from the book node, the book will be about a subject, so for the subject type, the direction will be in. And then we also, on the book type, we wanna be able to go from the book to the author and the book to the subject, so we'll say authors, I think, so a book can have multiple authors, so this I think should also be an array field and we'll need a relationship type, which we said was wrote, so from the point of view of the book, the direction is gonna be in because we're gonna go from the author in to the book. And then similar for subject, so a book can have zero or more subjects really and a relationship directive, so the relationship we said for this one was about, oops, missing our double quote there, so direction this case is going to be going out, so we're saying the book is about subjects, Andres says he's dropping. Yeah, thanks for joining, yeah, there is a recording I think that will be sent out and yeah, thanks for joining, okay, so we'll save this, I didn't command us, we can also go to up here file save, you can see this triggers a restart of our GraphQL API application, and I think we need to refresh this browser to get GraphQL playground to reload the type deaths, but now if we look in the docs, we should have authors, yeah, we have authors and subjects cool.

Okay, so we have this table, we need to write GraphQL mutations to add the authors to our books. So let's do that, so we have a book called Inspired that was written by Marty Kagan. So let's take a look at how to do that. So we're gonna delete that, this is gonna be, I know it's gonna be a mutation. And we need to decide what way we want to start. There are a couple of ways we could approach this. We could do update books and search for the book and then connect, or do a create operation rather from the book to create a new author, or we could do create authors. Maybe let's start with that. So we'll say Create Authors, author has a name, but Marty Kagan and then Marty Kagan wrote a book. We already have the database. So this is gonna be a connect not a create. So we're gonna connect where the node. So you may notice that we have to say, connect where the node if we had properties on the relationship. So we haven't talked about this yet, but so far we've been storing properties on the nodes. If we had properties on relationships, we would have another option here to filter based on the edge object, which is basically, which is anyway, that's why we have the node here, it seems like an extra layer, but it's simply because we don't have the edge filter cause we don't have any relationship properties. Anyway, we want to filter where the title is inspired and let's get some more real estate so we can see what this says. Then we'll bring back authors, name, and books in the title of the book. And then we also want the info to tell us if we create any nodes. Okay, let's identify this and look at this. So what are we doing? So we're saying create authors and here's the input object, create an author, set the name to Marty Kagan, then for the books relationship field, we're going to connect to existing books where the title of the book is inspired. So let's run that. And we say we've created Marty Kagan, and Community Inspired we created one node can verify this if we go to Neo4j let's look for author. Here's Marty Kagan, you can double-click to traverse out, you wrote this book inspired, which is all about product management. Cool, okay, great. So that was updating to our schema, adding authors and subjects. I'm gonna skip going through the rest of the authors and the subjects so we can move on and have time to cover the remaining section, but you can imagine how we use those nested mutation operations to create the authors and subjects. You can find the solutions linked in the sandbox too in the readme if you want to check that out. Cool, so let's move on. So we've talked about writing our type definitions that then drive the database, drive the graphQL schema that's generated that gives us the CRUD operations for creating data. What about custom logic? How does that fit in? That's what we're gonna talk about in this section. So I'm gonna do some setup here, you can follow along if you like, but you don't need to. Let's clear out our database. So because we were going through that exercise and we have somewhat different schemas, I'm gonna do another, match a, detach, delete a. So let's delete everything in the database and then we have a new code sandbox. Let's copy the link for this one, drop the link in the chat. Let's do that again. So this is a new code sandbox, which means we'll need to update our.env file again. So I'm just gonna copy that from this code sandbox. I'm gonna click that link that I pasted in the chat and then we wanna fork this code sandbox. So we get one that is private to us and I'm gonna paste my credentials into that.env file and save that. So our API application will restart. So this schema now includes a bunch of other things. It includes the author. Yeah, so author subject. We also have these cypher directive fields now where we've added some custom logic. We even have a new weather type and if we look in Index.JS we see we've actually like implemented a resolver here. So this code sandbox, we're going to talk about in the context of adding custom logic. So you want to follow along with that code sandbox, you can see some updated code, but to finish the set up we need to run this mutation to create some data based on the correct full schema. So that included authors and subjects. So that is running to save some data in our Aura instance. You can see we're creating the authors for each book, the authors for each book, handful of books, and then creating customers and some orders. I guess there's a couple of notations operations here. Okay, cool. So let's talk about custom logic. So we get a lot that is sort of generated for us for free essentially by the Neo4j GraphQL library based on our type definitions.

21. Adding Custom Logic with Cypher and Resolvers

Short description:

There are two ways to add custom logic in GraphQL. One is using the Cypher GraphQL schema directive, where we add custom logic by adding Cypher statements to the schema. The other approach is implementing custom resolvers, where we can call out to Neo4j or another database. Using the Cypher schema directive allows us to include the custom Cypher statement as a subquery in the generated Cypher statement, avoiding multiple round trips to the data layer. Implementing custom resolvers may result in multiple round trips to the data layer. We can use the Cypher schema directive to compute scalar, node, object, and object array fields. For example, we can calculate the subtotal of an order by traversing the books in the order and summing up their prices. We can also use the Cypher directive to find recommendations for customers based on their orders and similar preferences of other customers. These recommendations can be nested and queried as well.

There are two ways though to add custom logic. So if we have business logic beyond just our basic create read, update, delete functionality. So the two approaches to that, one is the Cypher GraphQL schema directive. So this is where we're adding custom logic by adding Cypher statements to the GraphQL schema or implementing custom resolvers. So we can implement custom resolver functions with any logic, we can call out to Neo4j and call it another database. We can basically do whatever we want in a custom resolver. So there's some trade-offs here. So if we use the Cypher schema directive, the benefit we have here is that even though we're adding a custom Cypher statement, that statement is still included as a sub query in our single generated Cypher statement. So we still are only sending one query to the database. So just one round trip to the database our custom statements are integrated into that one generated query. So we get to take advantage of the performance benefits even though we're adding custom logic. We're not sort of going down that path of multiple round trips to the data layer with this going down the path of the N plus one query problem. If we implement custom resolvers, well, those customers resolvers those are still called in a nested fashion. So we may end up making multiple round trips to our data layer in that case. So something to be aware of there. And of course, implementing a custom resolver it's a bit more work than just attaching a cipher statement in our type definitions. So we saw an example earlier of the cipher schema directive. I think it was looking at a business recommendation like a collaborative filtering for users who reviewed this business. What are other businesses those users are reviewing? If you like this business that might be a good way to find recommendations. So let's look at the different ways that we can use this cipher statement. So, and these snippets all come from the code that's in the code sandbox. So that code sandbox link for this module includes all these examples. So you can run these and see how this works. So here we are adding a field to order, using this extend syntax in GraphQL SDL, which we can add these as fields on the type definition. I like to use this extend functionality because then I can sort of have my basic type definitions in one place and my custom logic somewhere else and add them together. But it's just a syntactic sugar I suppose. So here we're adding a sub-total field to the order type. So we may calculate this by looking at the order, traversing to all the books that are contained in the order and then summing up the price of each book. Of course, this could be a bit more complicated. We may have discounts and things like that to take into account. But this is one way that we can calculate sub-total. So here we're using the cypher directive to compute a scalar field. So we're calculating a float. And again, note the use of the this. This is a variable that's injected to refer to the currently resolved order. And so to the client of our GraphQL API, this just looks like another field, right? It's not obvious that this is actually being computed. Let's look at this one as an example. This is interesting. So in Playground, oh, we've got an error on this. I don't know why I didn't get an error. Oh, maybe I didn't paste in the right credentials in my.env file, perhaps. Is that what happened? Copy. Paste. And we're in this again. There we go. I worked out time. Yeah, so I think I didn't have the right credentials from my database. But, okay, so what do we want to do? We want to look at orders. And for orders, orders have what? An order ID and a subtotal. So let's run this. So here's all of our order IDs and the subtotal. Now, if you look at the generated cipher quarry, so I gotta scroll way down in the terminal output. If I look at the generated cipher query for that, I can see, okay, we're matching on order, we're returning order ID. And then for the subtotal field, here's our cipher query that we attached to the schema where we're traversing to all the books in the order and summing up the price to get sub total. So that's what we mean when we say that the cipher statement that we're attaching with the cipher directive, that that is sort of injected as a sub query into the one generated cipher statement. So we're still making just one request to the database. Okay, so that's using cipher schema directive on a scalar field. We can also do this to node and object fields and object array fields. So here we're adding a recommended field to the customer type. This is an array of books. So we're looking at the orders that this customer has placed. So starting from this, it's the currently resolved customer, traversing to orders this customer has placed to books that are in the order, and then looking at other orders that contain these books that other customers have placed. So this is saying for all the books that I've ordered, what customers are also ordering the same books that I like? So basically finding similar customers, right? Buy the same books, similar preferences. Then in the next statement, the next match line here, we're going from those other customers, what are orders they're placing with other books that I have not ordered? So what customers are ordering books that I'm also ordering? What other books are they ordering? Those might be good recommendations for me. Again, this is another way to express this idea of collaborative filtering where I'm using the preferences of other users in the network to personalize recommendations for a specific user, which we can express in Cypher. So now we have this recommended field on customers. And again, we can query this. I'll probably skip querying this one in the interest of time here. But now we have this recommended field that gives us books. We can select into books and continue on like a nested structure as well.

22. Field Arguments and Default Values

Short description:

Field arguments in type definitions for Cypher directive fields are passed as Cypher parameters. Default values can be set to handle cases where no value is provided. For example, the limit field argument can have a default value of three, but it can be overridden to return only one recommended book.

Any field arguments that we define in our type definitions for the Cypher directive fields are passed to the Cypher statement as Cypher parameters, which is quite nice. So for example, on our recommended field, we want to control the number of recommended books. We could add a limit field argument here, and then that's available to us in the Cypher statement as a Cypher parameter. We use the dollar sign to indicate that we want to use a Cypher parameter in that name, matches whatever is included in our Cypher, in our GraphQL argument. Sorry, I have some loud noises going on.

Okay, so this is quite nice. It is a good idea, I think, typically to use default values here. So here we're setting a default value for three. That means we'll, this limit Cypher parameter will always have a value, so we don't need to think about how to handle that in the case if we don't have a value that the user specifies. So we could also, you can also make it a required input, but I like to set a default value. That makes it easy for the client, if they don't care, they can just use the default value. But then we don't have to in our Cypher statement to handle the case where no value is provided. Anyway. So here, we're overriding that default value by saying, no, we only want one recommended book.

23. Custom Logic and Resolvers

Short description:

We can use Cypher directive fields to return objects and map them to types defined in our schema. For example, we can call out to a weather API in Cypher, retrieve weather data, and project it as an object field in our GraphQL API. We can also use Cypher directive fields for top-level queries and mutations, such as implementing fuzzy matching through a full text index. Additionally, we can add custom logic by implementing resolvers, which are generated by the Neo4j GraphQL library. Resolvers allow us to specify data fetching logic and override the generated resolvers. We can also add custom fields that are not stored in the database by implementing resolver functions. The ignore directive is used to indicate that a field should be resolved using a custom resolver instead of fetching data from the database. Finally, we have an exercise on calculating similar books using Cypher. The last module of the workshop focuses on authorization, and there is a specific code sandbox provided for this topic.

Okay, so we've used the Cypher directive for scalar fields, we've used it for returning nodes, we can also use Cypher directive fields to return an object and Cypher, I think we call these maps, but an object, a map, a dictionary. Every way I think about it, key value pairs. So we can use, write a Cypher statement that returns an object, and then map that to a type that we've defined in our schema. So for example, in this case, we have address nodes. It may be helpful for our delivery drivers, for them to be able to see the current weather at these addresses where they're going to deliver things. So here we're using Cypher to call out to a weather API. We're using APOC. APOC is the standard library for Cypher that adds some additional functionality. So one thing we can do with APOC is call out to other APIs. So here it's APOC load JSON, call it to adjacent API to then work with the JSON data that comes back from this weather API. But note that we have the location, latitude, and longitude available to us because this, which is the currently resolved address address has location property. Then we return this object. So temperature, wind speed, wind direction, precipitation and summary that matches this weather type that we've added to our schema. So this is good for this case where we may be calling out to another API to fetch some data and we just define some types that don't necessarily need to exist in the database. So we don't have weather nodes in the database, but that's okay. We're projecting those from a Cypher statement. And again, to the client of the API, of our GraphQL API, there's no indication that this is calling out to another system, that doesn't actually exist in the database, whatever, like they don't even know that it's coming from a database. It's just another object field current weather. So, so far we have been using these Cypher directive fields on types. So we've been adding fields to types. We can also use them for top level queries and mutations. So for fields on the query and mutation types. Why would we do this? Well, one case might be to expose fuzzy matching through like a full text index or some custom query logic. So we can create a full text index in the database with this statement, which I'm going to skip running in the interest of time here. But then we can query the full text index and specifically indicate we want to use fuzzy matching. That's the tilde at the end here. So we're searching for books that have either a title or description that contains graph but always misspelled graph. But we still want to return useful results to the user, so that's what the tilde indicates. This, by the way, this is a query syntax supported by Lucene. Lucene has a full text engine that is the backing for full text indexes in the Neo4j. So that's the Lucene syntax. So any sort of Lucene syntax we could use here. Okay, so that's how we query it in the database though. How do we expose this through our GraphQL API? Well, here we're adding a book search field to the query type. This book search field takes a search string field argument. We're passing that search string into our Cypher statement to search the book index. We're adding the tilde to indicate we want fuzzy matching. So we've now added a full text backed fuzzy matching field for, searching for books. So now if we search for books and we even misspell graph, we'll still get some useful results. So that's one case where we may wanna use Cypher directive for a custom query fields. We can do something similar for mutations. Maybe we have some custom mutation logic that we have. We have some very specific structures we wanna create, or we have some specific way that we want to load the data. We can create a mutation fields where the logic is defined using Cypher as well. Okay, so those are the different ways we can use the Cypher directive. So custom mutation, custom query fields, scaler fields, returning nodes and projecting objects from Cypher statements that don't actually, or may not actually exist in the database. Another way that we can add custom logic is by implementing resolvers. So resolvers are generated for us by the Neo4j GraphQL library. We haven't had to write any resolvers yet. We have all of this, including custom functionality in our GraphQL API, which is pretty neat and super powerful. Usually we are writing resolvers just to specify the data fetching logic. We can override the resolvers that are generated, or if we have data that is not actually in the database, we want to call it some other system, whatever the case may be, we can implement resolver functions. So here we're adding a field to the order type called estimated delivery, which is a date time. So maybe we have like a logistics system or something like that that we're calling out to, that's going to tell us if we have this in stock and when we think we're actually gonna be able to ship it. In our case, we're just calculating a date at random in this function, but imagine doing something more complicated. Here, we're just calculating a date kind of at random. So when we do this though, we need to add the ignore directive to our schema to indicate that we should not just try to fetch this field from the database, that do not include the estimated delivery field in our generated cipher statements, because that is not data in the database, instead actually call this estimated delivery resolver to get the data for this field. And so this becomes then another field available on our order type. Okay, so we have another exercise. I'm gonna skip this one, we'll leave this for you to do on your own time, since we have only about 10 minutes left. But if you look at the code in the code sandbox that is linked, you'll see a similar field on the book type. And the exercise here is, think of other ways in Cypher that we could calculate similar books, try to modify that, see what the results look like based on that. But we'll leave that for a home exercise, I guess. Okay, so we have 10 minutes left for the final module, which is on authorization. There is a code sandbox specific for this one. Let me go ahead and bring that one up. I think we'll probably let's just talk through the examples here. Let me copy this, copy link. So here's the link to this one, which I will drop in the chat. I shared this link earlier.

24. Authorization with Auth Schema Directive

Short description:

Let's talk through authorization using the auth GraphQL schema directive. We use JSON web tokens to verify claims and match rules defined in our schema. JSON web tokens are signed JSON payloads encoded into strings. We can define rules such as authenticated, based on roles, allow, where, and bind. These rules protect types and fields in our schema and ensure that only authorized users can access certain data or perform specific operations. We can also use authorization functionality with cipher directive fields to access claims in the decoded token and generate recommendations based on user data. There is an exercise to create a new user and add data from their perspective. Thanks for joining!

You also find all of the queries that we're running here as well in this gist.

Okay, so let's talk through authorization. There is another schema directive available in the Neo4j GraphQL library that is super powerful called the auth GraphQL schema directive. Auth allows us to define authorization rules to protect types and fields in our schema. We use JSON web tokens to verify claims and match those two rules that we've defined in our schema. If you're not familiar with JSON web tokens, it's basically a way to cryptographically sign a JSON payload, and then it's encoded into the string. Anyone can decode these. So you can take any JSON web token. There's this online tool JWT IO, paste it in there, you can see the payload. And then there's a separate key that either a secret string or like a public-private key pair that's used to verify that the token was signed. In our case like signed by an application that is verifying those claims, either by using a shared secret or by signing it with the private key. And then we're gonna use the public key to verify that it is a valid token and that the claims or the payload, the data that's JSON object, that those claims are valid. So in this case, we have a sub claim, that's the subscriber, which is like the user. User ID, that's typically what's used there. Then we have roles. So this token is a valid token verifying that the user is BABLABLA7687 and this user has an admin role for this application. There are lots of other things. So we can add basically any sort of JSON key value pairs to the payload of a JWT. There are some conventions such as sub is commonly used for subscriber roles, scope, things like this. Okay, so let's look at some of the rules that we can define using this off schema directive. So the simplest one is authenticated and this simply means that in order to access the field or type the GraphQL request must have a valid JWT. In the request header. So here's an example where we've added is authenticated to subject. So maybe, I don't know. Maybe we have like a public search for our books and then you can view like the title and author but if you wanna do the subject you need to sign into our application, something like that. So we get an error if we request subjects and we are not passing a token but here we've added an authorization header in GraphQL playground with a bearer token. This is the JWT and the Neo4j GraphQL library will validate that the token is valid by using either a shared secret or a private key and then we will get the data that we expect. The next type of rule we can create is based on roles so we saw that token before that had a roles claim and it was an array and included admins. This was an admin user. By the way, we can also specify the operations for each one of these auth rules so we're saying this rule is gonna apply to create update and delete operations on the book type so this rule will not be applied to read so anyone can read but to create, update or delete a book you need to have an admin role. Another type of rule we can define is allow. Allow will compare values in the database to values in the payload of the JSON web token so here we're saying that to have access to an order we're not specifying any operations here so this applies to all operations for the order including reading that the customer username of the order needs to match the sub or the subscriber claim in the JWT So this says users can only read their own orders or create or update their own orders. So here we are authenticated as this user ML from 7474 and we're saying show me all of the orders for this user but now if I remove that filter and I say show me all orders. Well I'm trying to request orders that I don't have access to as I'm gonna get an error. We can combine multiple rules. So this is an or operation. So we're saying only customers have access to their own orders. Or if you're an admin, if you have an admin role and you also have access to orders. So there's a problem sort of with this one where we're authenticated, we're asking for all orders. We still get an error because we're not filtering for orders for the currently authenticated user. So there may be some cases where we don't really want the client application to be responsible for adding these filters to filter for only the currently authenticated user. So that's where the where rule comes in. So where is similar to allow, and it allows us to specify rules, matching values in the database to values in the JSON web token. But the difference to allow is that where will automatically add those predicates to the generated Cypher query so that the client can, it's free to request data, but that predicate is always going to be added. So they're only going to get back data that they have access to. So here we're adding a where rule to the customer type that says only the currently authenticated customer can access the customer type. So you can only access your own customer data. And now we're authenticated as a specific user by passing this authorization header and passing this bearer token. We're asking for all customers, their username and their orders. But if you look at the results, we're only getting back customer information for the currently authenticated user because we've applied that where rule. Bind is another rule that we can create. This will also match data in the database to data in the JWT. And in this case, we are saying that to create or update a review, the author username of the review, so note we are like traversing the graph a little bit in this rule, we're going from the review to the traversing the wrote relationship to the customer, we're saying that the username of that customer who wrote the review in the database, that username needs to match the subscriber claim of the JWT. So only users can create or update their own reviews, which makes sense. And bind means that this will be applied during mutation. So if we try to author a review and we try to create, connect that review node to a user other than the user or the customer that we're currently authenticated as, then we get an error. We can use authorization functionality with cipher directive fields. So we can define is authenticated rules for cipher directive fields, and then also in any cipher directive field, when we've configured authorization, we have access to all of the claims in the decoded token, which is really neat under the auth cipher parameters. There's an auth cipher parameter, so say auth.jbt.sub in this case right here on the first line of our cipher statements to refer to the currently authenticated user. So we can grab their username from the token, look that customer up in the database. And then here we're generating book recommendations for the current user. So again, here we're looking at what books has this user purchased, what are the subjects of those books, what are other books that have those similar subjects. So recommending books based on similar subjects. So this is nice because we can just have a Books for Current User query field, we don't have to like filter in that GraphQL query to specify the currently authenticated user that's grabbed from the claims in the token from this authorization header, and we get back recommended books. Cool, so we're over time, there's one more exercise, which is to create a new user using the Admin Bearer token, then create a JWT for the new user, signed with a secret, and then add some data from the perspective of that user. So I will leave that for a home exercise since we are out of time, the solution I think is included in this gist that I linked, yeah, down at the end here. Cool, so thanks everyone for joining and for sticking through to the end here. Thanks a lot. We have a lot of other interesting things that we can do with the Neo4j GraphQL library that we didn't have time to cover today, like working with unions and interfaces. There's an OGM package as well that allows us to have a programmatic API that uses GraphQL type definitions, which can be kind of interesting.

25. Conclusion and Upcoming Workshop

Short description:

We briefly discussed relationship properties and provided links to documentation for further exploration. The Graph Academy offers self-paced training for a more in-depth understanding, using the same bookstore API application. We will be conducting another workshop on Tuesday, December 7th, focusing on building full-stack GraphQL applications using Neo4j Aura, Next.js, and Vercel. If you're interested, join us to learn how to deploy a complete application with both backend and frontend components in React.

We talked a bit about relationship properties, but we didn't actually do anything with them, just aggregations and so on. So lots of other interesting things. These are links to the documentation for each one of these topics if you wanna dive in more. Here's this list of resources again, the slides everyone should have, the code is online so you can find that.

One thing I will mention is this Graph Academy training. If you wanna go in more depth, the Graph Academy training is like self-paced training you can do on your own, you get a certificate when you're done. It's similar content to what we covered today, but in a bit more depth, it uses the same bookstore API application.

Cool, well, again, we're over time, so I think we will stop here. I'm doing another workshop through GraphQL Galaxy on Tuesday. If you're interested in that, let's take a look. GraphQL Galaxy, where are the workshops? Where are the workshops? So, this is this one, building GraphQL APIs with the Neo4j GraphQL Library. We've done that one. On, I think it's Tuesday. Yeah, Tuesday, December 7th at 1800 CET, we're going to do a workshop with looking at full stack GraphQL applications using Neo4j Aura, Next.js, and Vercel. Today we focused just on building the backend piece and the database and the API layer. On Tuesday, we're going to see how to use Next.js to build really a full-stack application that includes the backend piece, but also the front end, and then how do we use Vercel and Neo4j Aura to deploy our application? So, we'll do some things in React. So, if you're interested, feel free to join on Tuesday, otherwise that is all I have today.

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
Remix Conf Europe 2022Remix Conf Europe 2022
195 min
How to Solve Real-World Problems with Remix
Featured Workshop
- Errors? How to render and log your server and client errorsa - When to return errors vs throwb - Setup logging service like Sentry, LogRocket, and Bugsnag- Forms? How to validate and handle multi-page formsa - Use zod to validate form data in your actionb - Step through multi-page forms without losing data- Stuck? How to patch bugs or missing features in Remix so you can move ona - Use patch-package to quickly fix your Remix installb - Show tool for managing multiple patches and cherry-pick open PRs- Users? How to handle multi-tenant apps with Prismaa - Determine tenant by host or by userb - Multiple database or single database/multiple schemasc - Ensures tenant data always separate from others
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
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

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.
React Day Berlin 2022React Day Berlin 2022
29 min
Get rid of your API schemas with tRPC
Do you know we can replace API schemas with a lightweight and type-safe library? With tRPC you can easily replace GraphQL or REST with inferred shapes without schemas or code generation. In this talk we will understand the benefit of tRPC and how apply it in a NextJs application. If you want reduce your project complexity you can't miss this talk.
GraphQL Galaxy 2022GraphQL Galaxy 2022
29 min
Rock Solid React and GraphQL Apps for People in a Hurry
In this talk, we'll look at some of the modern options for building a full-stack React and GraphQL app with strong conventions and how this can be of enormous benefit to you and your team. We'll focus specifically on RedwoodJS, a full stack React framework that is often called 'Ruby on Rails for React'.