 Welcome, everyone. Next, we have talk on building GraphQL APIs with Ariadne, a schema-first approach by Rashmi and Prajalesh. Please welcome Rashmi and Prajalesh, stages all yours. Hi, everyone. I'm Rashmi. With me here is Prajalesh. We're so excited to be here. Our topic is talking on building GraphQL APIs with Ariadne, a schema-first approach. So let's get started. A little bit about us. I have a couple of years of work experience. I've worked at Intuit as a software engineer. And now I'm currently pursuing a graduate program at Carnegie Mellon in the US. Prajalesh here is a senior software engineer at Intuit. He has over six years of experience with a variety of tools and technologies. Let's get started with our talk. The agenda that we have for today is we're going to walk you through what GraphQL is. And then we're going to show you the difference between GraphQL versus REST, how you do it conventionally. Then we're going to talk about two integral components of GraphQL, which is schema and resolvers. And then we're going to go on to the core of our topic, which is Ariadne. Ariadne is a Python library that helps you build GraphQL servers. So they're going to talk about that. And then we're going to talk about how you can get an application up and running using Ariadne by writing schemas with it and by writing resolvers with it. So let's get started. I'll hand over the stage to Prajalesh to start his presentation. Thanks, Reshmi. So hi, everyone. So it feels good to be here at PyCon. So let's get started. So you have probably heard of GraphQL. So it was developed by Facebook in 2012 and it was then known as Supergraph. So it has had huge rising popularity across all major tech companies over the last few years. And of course, now it is known as GraphQL. So what is GraphQL? So this is the definition that you're probably going to come across in the GraphQL website and anywhere else. So what it means is GraphQL is a query language and it's a runtime. So it tells the client how to make queries and it tells the server how to resolve these queries. So we are going to break down this definition as we go on. So let's get started. So before we get started, I just want to clarify that GraphQL is a specification. It's not tied up to any particular language nor a framework or specific to a particular data storage mechanism. So we can use GraphQL specification with language of our choice. If the data storage could be a flat file, it could be a SQL database, it could be a non-SQL database. So to understand GraphQL even more, so let's look how GraphQL compares to REST. So for this comparison, let's take a scenario, let's say we have a library service which exposes a couple of APIs and we have a client who is trying to figure out what are the most popular books for each order. So let's say these are the two APIs available. So we have an order and point which gives the list of orders available in the library service. So we get the ID, name and nationality of the order and we have a book and endpoint where we have to pass the author ID. So we get the ID, name and bunch of other information related to the books. So we get the rating information of the books, that is what interested us. So now that we know how we are going to get the data, so let's see the scenario, how we will get the most popular book for each of these orders. So first we will make a call to the orders endpoints to get the list of all the orders. So we'll be using ID of the order. So let's say like we take the first ID of the order, then we will go to the next API call where we will hit the books API with the orders ID where we'll get the list of all the books for that particular order. So here we got the information about all the books related to that particular order. So what we will do once we have the list of all the books, we will do some sort of computation our client side to sort it based on the rating, then we get the most popular book for that particular order. So we will do the same operation for all other authors as well so that we get the popular books for all the others in the library service. So let's see what we have done so far, right? So we actually made a total of n plus one calls. The first call to get the list of others, then each of the orders, we have to make a call to the books end point with the orders ID to get the details of the books. That's this total of n plus one calls. And when we, if we look back to our response, we had a bunch of additional information which we are really not using. Like here we have the nationality of the author and in the books response, we had a bunch of other information which we didn't use. All we used was rating and name of the books. So how does GraphQL handle the same scenario? So that's what we are going to compare here. So with GraphQL, we would make only one call. So authors and books are interrelated and GraphQL preserves these in its schema. So we can get all the interrelated data in one request. So we have to make only one call and we get exactly the data that we have requested. We won't be getting any extra information. So we will delve deeper into each of these points. So these points tie back to the definition of GraphQL that we looked at in the start of the slides. So we will see how it tied back in the later slides. So let's look at the first point where we said we will hit only one endpoint. So on the left side, we have the bunch of endpoints which are exposed by the rest. On the right side, we have the single endpoint used which we will be using on the GraphQL specification. So how a user will be able to get the data hitting one endpoint. So how the user know what all data is available to query from this endpoint. To solve this problem, GraphQL uses something called a schemas. So every GraphQL server exposes a schema that can be used by the client to understand what data is being exposed. So schemas are nothing but which defines the kind of data that can be queried from a service and how we define it. We use something called schema definition language. So if we go ahead and look at a sample schema, how our library service will look like. So this is how it will look like. So it is pretty intuitive to understand. So we have a bunch of types here. Like we have an other type. And we have data related to other within it. So similarly, we have the book type here and we have bunch of data related to books underneath that. So these type represents the data that is of interest to our system. And within these types, we have fields. So the book type has bunch of field called name, other ratings and so on. So if you look at that, at the end we have a special type called query type. So we will talk about it in the coming slides. So what are root types in a schema? So GraphQL has like a couple of root types. So these types defines the operations. So we said types actually represents data, but root types actually represents the operations. The query root type, which we have seen in the previous slide specifies how we can query a data from the GraphQL schema. Whereas the mutation type, in mutation type we will specify what or update or create operations we can perform. So query is for getting the information and mutation is for updating the information using the GraphQL endpoint. We have a special root type called subscription, which is more like instead of querying the server will notify the client upon whenever there is an update in the data. So now we will look at what are object types and field types. So when we looked at our schema, we saw the other type and the book type. So these types are called object types. So they represents object that are of interest to us. The object has fields, which as if we look back to our book type here, it has field called ID, name, rating, which are of scalar types. These are like integer, floats, those kind of fields. So we call them as scalar types. And we also have another type within book, which is of type objects. A type can have scalar type, scalar field as well as object field within it. So this is how a graphical representation of our schema looks. So we have query, other and book type and bunch of field associated with it. So now let's look at how the schema breakdown here. So we know that query is the root type and author and books are the object type and we have multiple fields. So we have color coded, the scalar field in yellow and object field in green in color here. So now that we looked at the first point, like how GraphQL was able to get us everything in one call, GraphQL is something called schema. Schema put our data together so that we can get all the interrelated data in one request. So this tied back to our definition, which is GraphQL is a query language for our APIs. Now let's look at the second point where it says we can retrieve just the data we need. So how we are doing that? So let's look at example query. So here we can see a query which we used to pass to the GraphQL endpoint and we need some data. So we are requesting for the author's information and we need the name of the author and the books related with the author. So we are requesting for name and rating of the books. On the right side, we have the response from the GraphQL endpoint. So we got exactly what we have requested for. So one interesting thing to note here, so we got only what we have requested and we got in the exact same order that we have requested for. No extra data and we got exactly what we have requested. So like the second point says, the data you need in the way you want, no more, no less. So how is GraphQL able to do this? So GraphQL uses something called as resolvers to fetch these informations. So whenever resolvers are functions that is responsible for populating data for single field in your schema. So if you look back to our books type, so we have a bunch of fields there. So each of the field, there will be a resolvers associated with this. So whenever a client called for a particular query with a bunch of fields, what GraphQL does beneath this, it calls the resolvers associated with each of the fields, which internally pull the data from the source. So here we show like each of the type and we have the fields and corresponding resolvers there. So the query type, we have resolvers for authors and book by name and we have the authors and books and it's field and it's resolvers here. So then do we have to write all these resolvers to get the GraphQL up and running? So in fact, many GraphQL libraries will let us omit writing resolvers for scalar types and it automatically resolves it based on the object it belongs to. So if you look at our case here, most of the libraries that we use, we just have to write resolvers for the authors and resolve book by name. So all other scalar types are handled automatically by the library itself. Now let's take a look at what happens when we make the call to the GraphQL endpoint. So we know we have the schema, we have the query from the client and we have the resolvers for each of the field in the schema. So let's see like how GraphQL gets exactly what we want, right? So when the client makes a call to the GraphQL server, it will be either a query operation or a mutation operation. So resolvers for the query or mutation is where it all starts. So in our case, we are doing a query operation and we are requesting for the list of authors. So the query resolves the authors and it internally called the resolvers for the authors and authors call the resolvers for name and the books. So since name is a scalar types, the names get resolved there and since books inside books, we are requesting for name and the rating of the books. So it calls the resolvers for rating and name and we get those data as part of the response. So whatever we highlighted here in green are the resolvers that are being called from this query and this query is getting executed. So we can see it's or not all the resolvers are getting executed. So only the resolvers that are part of the query we actually requested in are getting executed and if you look at the leaf nodes, all the leaf nodes are of scalar type here. So now we know how GraphQL is able to fetch us the information in one API call and how we were getting the exactly the data that we have requested. So now let's look at the libraries and tools for GraphQL that are available in Python. So these are some of the mostly used libraries. So we have area, we have Graphene and we have Strawberry and so on. So if we go to the graphql.org slash code, we can see a bunch of other libraries that are available for Python and other languages as well. So in this talk, we will be covering more about Ariadne library. So Reshmi will walk you through the Ariadne library. So over to you. Hi everyone. So let me get started with Ariadne. So Ariadne is a Python library. What it does is it helps you bring built GraphQL servers. It's very simple. It's super easy to use and it has a bunch of great features. But the most essential thing that you need to know about Ariadne is that it is a schema-first library. We haven't actually walked you through what a schema-first library is. So that's what I'm gonna talk about now. So historically there have been two ways that you go about in building GraphQL servers. You can either go down this code first approach or you can take the schema first approach. Different libraries do it differently. Ariadne does it with schema first. Schema first means that you first get the schema of your entire system in a file and then you write your resolvers and then you tie your resolvers and your schema together. This has its own pros and cons. The other way around is code first, which means you write your resolvers first and then you register all your resolvers and from your resolvers, you get the schema generated automatically by your Python library or any other library. There's a popular library known as Griffin in Python. That does it the code first way. Both of these have their own advantages and disadvantages. Like in schema first advantage is that your schema is a file. So anybody goes and looks at your code. The first thing, they can look at the schema and they'll have an understanding of the entire system. The other way around in code first, the advantage is that it's gonna be, there are gonna be less bugs because your schema has been pretty valid. It's automatically generated. You don't have to spend time debugging it. You don't have to spend time looking at the schema and checking for inconsistencies just because it was written by a human being and not a system. I can go on talking about the differences between code first and schema first, but it's a huge debate in the GraphQL world. Something that probably a simple Google search would get you through. But what I wanna put across in this slide is that Ariadne follows the schema first approach. So we first need to write the schema, then we write the resolvers, then we tie them together. So how are you gonna go about doing this? Right, how do you write schemas with Ariadne? So I'm gonna take you back to the library service that we've been talking about all this while. This is the schema for the library service. We have the author type, we have the book type, we have the things that you can query on, which is authors and books by the name. And Ariadne, for two ways, you can register your schema. The first is that you have your schema as a string. So you can literally pass your entire schema, all of this just as a string and it would work. It makes sense. But I would probably not suggest that because most of the time your systems are gonna be complicated, they're gonna have a lot of interrelations. So the more standard way of doing it is to write your schema in a separate file by convention known as schema.graphql and you load it into your system, into your program at runtime. And that's schema as a separate file. But whichever way you do this, you have to make sure that your schema is correct because you have written the schema written by a human being that are bound to be inconsistencies and something that's invalid. So there are functions that Ariadne provides you with that you can use to validate your schema. If you have your schema as a string, there's a function called gql. What gql does is it parses your schema, it checks if everything is valid and if it's not valid, it's gonna raise the GraphQL syntax error. Now, this is pretty descriptive. You don't have to go hunt around. If it finds a syntax error, it's probably gonna tell you which line of your schema the error is. It's pretty descriptive. And it's optional, but I recommend that you use it otherwise later down the lane, when you're building the application, you're gonna have trouble because you won't know where the error is coming up. So the first step you do is that you always validate your schema. And like I said, because doing it as a string is not really industry standard, you should probably go with schema as a separate file. And for that, Ariadne provides a function called load schema from path. The load schema from path function basically can get the .graphql extension file and it can parse it. You don't necessarily need to have it in one file. You can have a folder with a bunch of GraphQL files within it so that you can modularize your GraphQL schema. Whichever way it is, load schema from path will read it. It will validate it and it will raise a GraphQL file syntax error with the name of the file and the line in the file where the error is. So what I have right here is the entire code that we needed to get our library service up and running. So I'm gonna break this down for you. So right now we're looking at schema, right? So I have my schema, which is the para right here and I have a file called schema.graphql and I just loaded it into the system, right? So now you have your schema. What next? You are gonna write your resolvers. So what resolvers do as a recap to tell you is that resolvers are gonna get the data associated with each field you have in your query. So you have a resolver for authors, you have a resolver for name of the author, you have a resolver for books of the author. Within books you have the resolver for name and rating, right? So when you call these resolvers, these are probably gonna be data sources that you have. You're gonna have a database with a table that has a list of all your authors and you have another table with a list of all the books or maybe you have a flat file, it's fine. Whichever way it is, you're probably gonna write a function that's gonna get you the data, right? That function is conventionally, it starts with resolve underscore and then the name of the field that you're trying to resolve. But to be honest, it can be anything. So what I have here is a function that's called resolve authors where I'm gonna try and get the list of authors that we have in our database, right? Once you have the list of authors, how are you gonna tie it with this field, this particular field in your schema? How you do it is you have something called object type. Object type is a special class that's provided by Adyarni. And if you want to resolve a field, you first have to create an object, an instance of object type for the object itself, for the type itself. So authors is a field within query. So you create an object type of query. So if I go back, if you look at this, we also have books, right, books is an object type. You don't actually have to resolve any of the scalar types, books is an object type, authors is an object type. So you need to resolve both of this. So probably in your system, you're gonna have three different instances of the class object type, one for query, which is because it's an object type, one for authors because it's an object type and one for books because it's an object type. And so once you have these instances, you have to bind the field with the function, right? So I'm gonna say within query, within the type query, there's a field called authors. And I'm gonna annotate this function with this so that it binds the function to the field. And it's gonna look something like this. So in my database, I have a fetch authors call and I'm gonna write the resolve authors function here. And I have a query object type query here. And I'm gonna say within query, there's a field called authors. This is the function that resolves that field. And similarly for books, I'm gonna create, I'm gonna say, see, book is within author. So I'm gonna say, I have an object type of author and within author, there's a field called books and this is how I'm gonna resolve it. And that's about it. Most of the time, this is gonna be as simple as it gets. It kind of can be complicated initially to try to figure out the interrelations between your system because in a REST system, we're probably not gonna model the interrelations, but here we have to. So you kind of have some trouble trying to interlink two different things, but it gets easy as it goes on. So we looked at loading the schema. We looked at the resolvers. We have two sets of resolvers here. And then now we're gonna go to the final step, right? We have, we had an initial query. We have resolved authors, we've resolved books and we should probably get all of this inside. So tie all of this together. You have one final call to make. Let's call the make executable schema call. The make executable schema kind of puts together everything in your runtime, your schema and all of the object type instances that you just created. In our system, we have a query type and we have an author type, right? We have an object type for these, both of these. So you pass the schema and then you pass the query and the author. If you probably wrote a, you know, if you create an object type for books, you probably need to add that in this list too. Otherwise, it's not gonna work. So once you call make executable schema, it kind of, you know, puts everything into your runtime and you just have to call GraphQL of schema. And that's it. Because what Ariane does is it provides a couple of servers out of the box, like you have an ASGI server, you have a WSGI server, whichever one you prefer, you can just kickstart the application and get it running. As soon as it starts running in your local, you have something called a playground that pops up. A playground is something that almost every GraphQL server will expose. It kind of, you know, it encourages developers to explore the data. So you can actually look at the schema here. You can look at what each field in the schema means using the docs tab here. And but here, as you see, I have the query. I had run this code and I have written the query here, which was the query that we've been looking at for quite a while now. And it's authors, name, books, and the name and rating of the books. This is what we've been trying to get out from the start, right? And on the right side here, you can actually see the data that's being returned by the system. This is super cool. Everything is being resolved by Ariane. Like we said, scalar types do not need resolvers. We didn't actually write too many resolvers. We just wrote two, one for authors, one for books. And it kind of automatically resolves all of the fields, which are scalar. So this will just get you a very basic system, right? But Ariane does provide integration with a lot of these libraries that you probably are using in your system already, like Django, Flask, and a ton of others. So you should be able to build a large-scale application with what you just have going on right now. So taking a recap back, right? We looked at what GraphQL is. We looked at the difference between GraphQL and the REST API. And then we looked at schemas and resolvers, which are integral components. And then we looked at Ariane, which was the library which we used to build a GraphQL application up and running. Then we looked at writing schemas with Ariane, and then we looked at writing resolvers with Ariane. That's all we have for our talk. If you have any questions, please feel free to email us. I hope this helped you, you know, take a basic understanding of GraphQL and how you can use Ariane to build GraphQL service. Thank you, Rashmi, thank you, Prasilesh, for a wonderful talk. Yeah, it was much informative. And I'll encourage all the attendees to post their questions to Q&A session. And we have one question from Gautam. Let me just show it up. So yep, the question is, how to create a relationship between two table IDs in GraphQL? Okay, I'm not sure if I understand the question correctly. I'm assuming that you have two different tables that have two different things, like authors and books. And you're kind of trying to link both of that. So if you probably have a foreign key in your system, right? If you just look at the database layer, you probably have a foreign key, like the books is going to be linked to the author or the other way around. That works because if you go back to our slide here, that's all you need to do, right? Right here, I'm just making a MySQL call passing the author ID. And within books table, you have the author ID as a field, right? You have it as a foreign key. You can actually MySQL will automatically do all the filtering for you. That's all it needs. Most of the time, all of the functionality, like the core functionality are already provided by the database layer. MySQL is probably going to have all of that for you. It's just going to be a MySQL call that you make. And you just make sure that you call it under the resolver. That's all you need to do. It's going to be automatically tied. Great. I hope, Gautam, that answers your query. We have one more question. So the question is, can I know major advantage of GraphQL over rest? Any real-world selection? So we have, I'm not sure about real-world, but in companies and so forth, you, when you write a model in the real-world, right? You have so many interrelations, right? Like, Prajilesh talked about books and authors and reviews. And it's common in a library service that you have three different things. You have three different APIs that talk about three different things. But books and authors are tied together, right? So you probably have to hit two endpoints in rest. And if you're trying to get books and reviews, it's the same thing because it's two different objects. They have two different endpoints. And you have to hit both the endpoints to get the common data, no data that needs one of this and end of this. And that's what GraphQL tries to solve. That's what Facebook tried to solve when they came up with GraphQL. They tried to make sure that you can model interrelations because that's what Facebook is about, right? You have a post, you have a bunch of likes within it by each person. You have different comments within it by each person. They're trying to tie all of the information, different information, different real-world objects together. And GraphQL can do that, but since rest can't, because in rest, you'll have a harder time trying to model real-world interconnections. Cool. We have one more question. Just to base it. So how is the performance compared to rest? Performance, I'm assuming. Well, rest is, it's a protocol, right? You really can't say performance. Like, you know, I've seen rest APIs are really bad and all the way to like, extremely powerful for highly performing rest APIs. So I wouldn't bring performance into this, but if the question you're trying to answer is that, am I going to get any performance degradation just because they switched to a different specification, which is GraphQL for my APIs? You probably aren't. In fact, it's probably going to be faster. One advantage that I can tell you is that in a rest API, if you're not able to fetch something, it's just going to fail. It's going to return, hey, I don't have it. I'm just going to return 400 to you. But in a GraphQL, if it's not able to resolve one of the fields, it just omits that field. It gives you an error, but all of the remaining field, it actually returns to you. So you don't actually have a lot of trouble. So in that way, I would argue a bit more towards GraphQL, but you know, it depends on scenario, but it's a specification. So I wouldn't link performance with spec. Okay, cool. So we have couple of more questions. So I'll just quickly get it to you. So there was one question that was, if I would like to access the books and restrict anonymous access to authors, how should I do this on the resolver level or is there a better way to do that? Give access to books and restrict anonymous access to the authors. I'm not sure if I understand the question. Perhaps, feel free to email me. I'm emailing my emails right here. I'll put it up. And probably we can chat about it because I think I don't really understand the question. Rajesh, if you have any thoughts about this. Yeah, I think it's not about anonymous access. So we are giving a specifications, right? So it's how you can access the data. So I even, I don't know how, I don't think like restricting any of that layer. Yeah, that's the question here. Yeah, so anonymous. I'm assuming that you're saying that you wouldn't want people to read authors data. I'm assuming that's the question. That's probably gonna be taken care of by a different layer in your system. It's not gonna be GraphQL that's gonna do it because GraphQL has nothing to do with it. It's not gonna do it. You probably, you kind of have an integration with Django or Flask going on that will kind of restrict their access. Again, feel free to email us. We'll try to help you answer the question. I think we'll probably need more understanding of the question to answer this. If it is more related to access, like Rashmi said, we might have to add another layer with controls, authentication and authorization, which we can integrate with that. But if you look at just GraphQL, so we are just writing the specification how to expose the data and the client can query like the way the client wants. So we don't have to build like multiple end points or like multiple surveys for different clients. So client can determine what they want. Okay.