 Hello, Reclosure, my name is Jhara Antonelli. I'm here to talk to you about schema-driven development with GraphQL and site. Thank you for having me. In this talk, I will give a brief overview on what GraphQL is for those that aren't familiar. I'll introduce you to site, and then together we can build a Pets app on top of site using only three things. A GraphQL schema, a configuration file, and GraphQL's graphical interface, GraphIQL. Let's start with GraphQL. What is it? GraphQL is a query language for clients to interact with a server. A common misconception is that GraphQL is a database query language, despite its name, it's not. As well as the client-side element, GraphQL is used to handle query fulfillment on the server. Initially developed internally to Facebook for two years, GraphQL was open sourced in 2015 and has grown with the help of the community. It has a healthy number of tools, including GraphIQL, the browser ID to GraphQL, Gatsby, an open source framework that uses React, Hasura, a GraphQL engine using Postgres, and for closure, we have library's light listening for the server handling, and Regraph, which I've used a lot in reframe projects. At Jerks, we're developing site and grab, which I'll go into more detail on in just a moment. Finally, there are a significant amount of companies using GraphQL, notably GitHub, whose GraphQL is publicly exposed, Twitter, PayPal, and of course, Facebook. Now, let me give you a brief introduction to site. Site is a resource server built by Juxt on top of XTDB. XTDB gives site the benefit of an immutable, bitemporal content store. Site supports both GraphQL and OpenAPI. It works by simply putting resources, including your schema, into site, and it serves the appropriate webpages. Let me show you a short video that I've prerecorded of site doing just that. I want to put a picture of my dog, Cooper, into site, and then I want to go and view it in the browser. First, I need to get a token so that I have permission to do so. Then I use site's put asset to put Cooper into site. We head on over to the browser where before that image was not found, refresh the page, and then it's Cooper. Say hello, Cooper. So for the GraphQL, site uses grab. It's a small Juxt library implementing the full GraphQL specification. Lastly, there is no backend code required to write simple CRUD apps in site. Now we know a little bit about GraphQL and site. Let's see just how quickly we can put together a Pets app for us Juxters built on top of site. First, I will quickly show you the configuration file needed for site. Then I'll give a brief introduction to site at the REPL. And finally, we will write a Pets schema that we can put into site and then use GraphQL to perform queries. This is an Eden file that we're going to put into site along with our schema. We need this so that site knows how to handle the upset of the schema and what to do when we're posting GraphQL queries. It gets stored in site and dynamically loaded every time it's required. Let's head over to the terminal and put this resource into site. Before we do, I need to get an access token. I can do this using the site command get token. I have the password stored for the admin user in pass, the password manager. Now I can use post resources to post my GraphQL Eden file into site. As I showed you earlier, we can put assets into site. Let me show you how it looks to put a picture of Buffy into site. We use put asset with the file name and we tell site it is a image JPEG type. And then we provide the path at which we want site to serve the asset. We're also marking this as internal. Now we can head on over to the browser and visit that path and we get a wonderful picture of Buffy. Let me now take you over to the site REPL. I've actually got site running locally. Usually I would develop against Prodigy, but I'm a little bit worried that I might share some internal juxtaposed secrets with you all. I've seeded it with a small amount of data so we've got something to play with for our pets app. I can use put to put a document into site. And remember, site uses XTDB. So here's a valid XTDB document. It has an XTID and some more information about the pets. This one here is Buffy. If we evaluate that, we see we get a XT response. We can take the XTID for Buffy and ask site to show us the entity with E. That will just return the document of Buffy the cockapoo. In site, we can also run XT queries. Here, I have a query to return all the pets that satisfy the juxt site type pet and the juxt home juxt code Alex. If we evaluate it, we get Buffy back again. So site has got a concept of document type. We'll see later when we write our schema that this is linked to the type in the schema. Earlier, we added a type to the pet. I also know that we have the type person in site, which is used for our HR app. Now, if I run LS type on person, that will return all of the IDs for the documents containing the type person. Now, if I take a look at just one of those entities, we can see the shape of the person data. We're going to use this in our pets app because we'd like to display a small amount of data on our pets owners. Let's just stop and think about this for a moment because it really is a killer feature of site. We can build several different apps on top of the site server, but there is a single source of data. In this case, we already have people stored in site and instead of adding or duplicating a lot of those entries when we come to add owners, we can just reuse them. That means that there is a single point of update so our data doesn't get out of sync. Likewise, if another app wanted to use our pets data, it could. Now that we've done our housekeeping, all that's left to do is write a GraphQL schema. The schema is really going to be the core of our pets app. From here, we're going to be able to shape the way the data is viewed and dictate the actions that are made within the app. I've outlined the elements that our schema is going to need already. So let's start by defining our schema. We're going to have both queries and mutations. Now, we can define our types. First, we'll define a type pet. On that, we'll need an ID. This will be used as the XT ID. And we'll give this a type of ID. ID is one of the few scalar types that GraphQL comes with out of the box. The others are integers, floats, strings, and booleans. Using an ID signifies that it's not intended to be human readable, and it should also be unique. Next, for our pet, we would like a name, a breed, and a species. These can all be strings. We can also have a list of strings for our likes and dislikes. And we need a string for our image URL. Finally, we need to say who the pet belongs to. That's going to be a string too. But if you remember from our pet's data, we added to site, this is a namespaced key. GraphQL doesn't have a concept of namespaced keys, but that's not a problem because we can tell site what key the data is under by using a directive. In this case, we use the attribute directive and we give it the namespaced key as a string. Now let's define our owner. Our owner has a type ID, a code with a directive, and a name. We also want to see what pets belong to an owner. The data we have for owners doesn't know anything about their pets, but that's not a problem because we can provide site with a query directive. That query will find all pets where the juxtcode matches the juxtcode on this object. The object in this case is the owner entity. Next, let's define an input. It's going to be useful to be able to have some search terms when we're querying our pets. Our search term input can simply have a key and a value. We're now ready to start defining some queries. It's going to be useful to see all pets. For this first query, I can simply return a list of pets. As I said earlier, site knows about types and because the pets have a juxtcite type value of pets and we're returning the type pets, without a directive, site will default to get all of the documents with that pets type. We've also provided an argument to this query so that we can use our search term input. Now, we can add a query for a single pet. If we give it an ID as an argument, site will match that ID to the xtid and return the entity. Next, we want to return all the owners. And finally for our queries, let's add a count. We can use an aggregate directive to count the type pet. This returns an integer. And with that, we have enough of our schema to put into site. Let's go and take a look at how it's shaping up. To put the schema into site, I can use the put graphql command with the file and the destination path as arguments. Now, if I head over to that URL, we can see our graphql file. We can also use graphiql to start looking at our pets. Let's take a look at all pets. There you go. We can see all of our pets here in the results. Let's see what happens if we add some search terms. We can search for the breed collie. And that returns all the breeds that contain the word collie. We can also control the number of fields that we return so we only get the values that we're interested in. Now, let's take a look at all owners. Oh no, that's not returning anything. Not to worry, let's go and fix that in a minute. Now, let's take a look at our single pet. We can give it the ID and return just the name. That works great too. And for our pet count, we can see that we've got nine pets. We can also add some search terms to our count. We can see that we have six dogs. Let's go and fix our owner's query. For the owners, site is looking for a type owner to return. But because we're using the people data, we don't have the type owner in site. All we need to do to fix this is add a query directive onto all owners so that we can find them. I'm confident that will work. So let's re-put our schema into site and we can run exactly the same query again without refreshing. And this time, we can see all of the owners and their pets. We can limit to just the name and that looks brilliant. But I think we can make this look even better. We already returned the owner code as part of the pet response, but what's stopping us from returning the whole owner object? Nothing, that's what. Let's modify the pet type and add a field for owners. Again, the pet's entity doesn't know any more about the owner than their juxtcode. But we can add a query site directive to look them up. This query returns the owner where the type is person and the juxtcode matches the juxtcode on the object. This time, the object is the pet. Let's post our schema again and take a look. Refreshing the browser, we can run our all pets query again with a name and a species on the pet. And let's return the name of the owner. And that works. We can see that this cat belongs to Malcolm. We can also go one step further and we can return the name and species of the pets belonging to the owner of the pet. So we can see that the owner of Kaya, Malcolm actually has two cats, Kaya and Arya. I think that's pretty cool. Now, the final thing we need to do to complete our pets app is add some mutations. With our mutations, we would like to be able to add, update and delete pets. For our ad pet, we'll return the type pet and we need an ID. For the ID, we can give site a directive to generate the ID if it's not provided. We also need an image, a name, breed, species, likes, dislikes, and an owner code. On the owner code, we can give another directive to tell site to store it under the key juxt home juxt code. For our update pet mutation, it looks much the same as our ad pet, except this time our ID is a required field. We also have a directive telling site that the mutation is an update. And finally, our delete pet has a required ID and a directive to tell site that this mutation is a delete. Let's put that into site and head on back to the browser. Now let's use our mutations to add Cooper into site. We filled in all of the fields apart from image just so that we've got something to update. I can choose to return some fields so I can return his name and we'll return the ID so we can use that for the update. That looks like it's worked. So now let's test our update. We can update with the ID that site generated for us and add the URL to the image. We want to just make sure that it is updating and not overwriting. So let's return a few of these fields that we filled in before. Excellent. Let's go over to our pets count and just make sure that we have the right number of pets now. There we are, we've got 10 pets. We can look up Cooper by his ID and double check that I'm still his owner. I am, so that's good. Now let's test out our delete. I don't really want to delete any pets that are already in there. So let's imagine we've accidentally added Cooper twice. So we can just run this mutation again because we haven't provided an ID and site doesn't have the directive on adPet that this is an update. We now have a duplicated entity of Cooper. So when I run my pet count query again we can see we've got 11 pets. So let's search for the ID we want to remove. We'll go for all pets and we want to find Cooper without the image and we can get the name. There we go. Let's grab that ID and test out our delete pet. Looks like it's worked. So we can go back to this query, search for Cooper and the pet count. You see we're back to 10 pets and we've only got one Cooper in there. So let me take you back to the REPL. So I can show you how site by using XTDB can keep a track of an entity's history. Let's require XT and we can get the entity history with our XT node. Using Cooper's ID we sort descending and we'll show the docs. If we look at the results we can see that there is a record of all of the updates we made onto this entity. The most recent one, we've got Cooper's image and the previous one or the original one, we don't. So because site uses XTDB it gives us the power to go back in time and have a look at what the entity looked like at a given point in history and this will be useful for auditing. Let's recap what we've done. We have made a fully functioning pets app in about a quarter of an hour. Put a document into site telling it about our app and write a GraphQL schema. This schema dictated how our pets app could be used. Imagine doing the same thing in rest. We've saved ourselves writing multiple endpoints to handle the same actions. A GraphQL is a powerful tool. The schema that we wrote today only scratches the surface. GraphQL also offers fragments which are reusable units of schema so we can save on duplication. Interfaces and unions which allow you to return one of several different types of object. On screen now is an example of a schema we're using with site on one of our projects. It shows that we can limit an offset searches in site. It also shows a union and an example of using metafields with type name so that with our results we can see the type that's returned. Another one of the benefits of GraphQL is that you can submit queries such that you only get the data that your app requires. You can also combine queries into one request so that you never have to over fetch or under fetch again. This means that your APIs can be cleaner and easier to manage. There's a really comprehensive tutorial on GraphQL's website that I can strongly recommend. Also there you'll find the spec which is really well documented if you're interested in reading further. With site you can use GraphQL to build powerful apps with minimal effort. If we wanted to, we can now make our own shiny UI and put that into site instead of using GraphQL. Site makes it possible for organizations to build multiple apps that can share data. We could use the people data that was already in site to serve as information for our owners. For our own site server inside juxt, we also use that people data for HR related tasks like assigning laptops or holiday and timesheet reports. To make this possible, we keep our documents small with only the information needed for a task. We can then build relationships between them using our XTDB queries. Lastly, I wanted to point out that site supports REST alongside GraphQL because there are some tasks like serving images that are best suited to REST. If you wanted to continue the journey with site and GraphQL, here are a few links for you to follow. Let me give a quick disclaimer though that while both Grab and XTDB are production ready and stable, site is still in an experimental phase. If you're interested in that though, head over to the juxt to YouTube where Malcolm and a few of us post regular videos of building site. And that concludes my talk. Thanks for your attention and thank you, Reclosure, for putting on another brilliant conference. I'm gonna be available in the Q&A panel after the talk to answer any questions you'd like to ask. Say goodbye to Cooper.