 Thank you. I think I will not use the microphone. Everybody can hear me, right? It's my voice loud enough. Yeah, kick it loud. Alright, because I need my hands so I can type stuff. Alright, so yeah, welcome everybody. It's cool that we can be here today and talk about APIs and especially GraphQL. I hope that friends in my introduction isn't like too similar, but we didn't really know that we both have the same topic. So I guess it's probably a good idea to hear the introduction from two different points of view because I also don't know too much about how GraphQL works under the hood. I just discovered it, started using it and fell in love with it immediately and I basically just want to share my enthusiasm about it. So maybe I can convince someone to start using it today or tomorrow as well, right? Okay, a little bit of an introduction about myself. So my name is Martin. I'm the CEO of the Outlink. It's a local Singaporean startup. We are like an online art gallery. We also have a mobile app called Last Love. I'm also the founder of Build Left Studio, which is a locally based web agency. Both companies are hiring, by the way, so if you want to work with React, GraphQL and all the cool stuff like Python and Django, you should reach out to me. You can reach out to me via Twitter and blog with my handle pretty much everywhere and you can just give me an email. I'm pretty sure I will share the slides with you. I have them on speaker deck so you can update the meetup page and then everybody will be able to download the slides and then you will be able to reach out to me. I also, unfortunately, after this, I have to leave immediately. I have some important stuff waiting for me at home. So if you have more questions after the talk, I mean I'm open to questions right after the talk but I have to leave and you won't be able to catch up with me so just shoot me some emails or treat me or whatever tomorrow or anytime later. So today I want to show two technologies. One is GraphQL and the other one goes in tandem with it. It's called Graphene Python. It's a way to use GraphQL at a Python developer. So both have nice websites so let's just look at it and it's essentially the GraphQL website is extremely well done. I don't really need to create any slides because I couldn't do it any better than these guys have done already. So what is GraphQL? It's a query language for your API. Okay, I kind of can understand that. So how does a query look like? A query looks like this. It's essentially just brackets and then you say I want to have something from my hero database, from my hero table and I want the column name and height. And the result looks exactly like what you have requested. It has the same structure. So you have hero again here and then you have the columns that you have requested with the values of that item. So it's a query language. That's really all it is. The cool thing about it is when you think about your app and when you think about ReactJS with all its components, who has used ReactJS? Sure, sure of hands. Anyone? No one? Okay, so you kind of have to use React on the front end but you can also use Angular and all these other fancy JS frameworks these days. Okay, but this might be a bit difficult to explain then. Basically, the idea of React is that you componentize your entire website. You might have a future component, header component, main navigation, main navigation item, maybe you have an avatar when you are locked in at the top right of your website. So you componentize the entire website and each component needs some data that it should display. So for example, when you think about the avatar component, it maybe needs to have the first name, last name of the user and maybe a link to the picture of that user. So this component can now write a query like this and say, I want the currently locked in user and I only want first name, last name and avatar picture. And you will have many of these components. So you will have many of these tiny, tiny queries. And GraphQL kind of allows you or essentially the client that you will use with GraphQL, which is either Apollo or Relay, allows you to collect all these queries and put them into one big query and send only one request to your database or to your back-end server. The back-end server will then go to your database, fetch all the data and send only one response back. So you save a lot of bandwidth and I will show this in detail later on my slides. So if you want to use GraphQL, what you have to do first is create a schema. You have to tell GraphQL how your database looks like. So you would say like, okay, my app has some character and they have names and each of these fields can even be subfields. So like your home world is of type Planet and Planet is its own database table, for example. And yeah, so then GraphQL has this cool thing called GraphQL, which is like a web editor or like an IDE where you can write your queries and it has like code completion so you can press control space and it shows you what kind of endpoints are available. So this is an endpoint here, all films, right? And then you wonder what's inside, okay, more films and what does a film have. And it shows you in the code completion the film has a title and a creation date and whatever. So you don't have to remember anymore how does my database actually look like or how many endpoints does my API have, right? So yeah, this makes working with it extremely nice as a developer. First thing you do in the morning, you open up GraphQL, you wonder like, okay, I want to build a component which needs an address of the user. So you just start typing users, address, and you have street, zip, first name, last name and all these things, right? And you don't have to look into your code anymore, look up these models or these database tables to figure out what's available. So it makes you really, really fast. Okay, so this is enough for introduction on the website. The other technology that we will talk about is graphene. So the problem with GraphQL is it depends what kind of database you are using. This dictates if you can use GraphQL today or not, okay? But I think most popular databases these days already have like GraphQL records available. And if you use something like GraphQL, a graphene, you can essentially write your own wrapper around any kind of data source. You don't even have to connect to a Postgres database. You could write your types and your fields. Sorry, just to confirm, so GraphQL directly to the database is not a wrapper around the rest of the library? Yeah, that's what I just want to say. You could essentially write a wrapper around any data source. In GraphQL, what you define is my application has a schema and there is something like a planet in my schema. But where it actually comes from, what kind of database it is doesn't matter. You will eventually end up writing functions like these resolver functions here. So in this example, it says, so my app has a query and there's one field on that query. So I would say this is similar to an endpoint, to a rest endpoint that we would normally in the rest API have. And this endpoint is called hello and its type is just a string. So when you call this endpoint, you always get back just a string. And in this example, it's even very static and boring. It always returns words. But these functions here, they are just Python functions and you can send requests to a Twitter API or to your Postgres database or to your MongoDB database and you just return whatever type you promised you will return on that field. So you can actually create a super monster API that gets data from anywhere. And you only have one endpoint. So everything goes against the GraphQL endpoint and it gets one response back. No more worry about what URLs does my API have and so on. You don't have to document your bloody API anymore. There is only one endpoint and it documents itself. You just start typing in the GraphQL editor and it shows what's available. The GraphQL homepage doesn't show much more. So let's just dive into it. So I like to have, in my presentations, I like to show real code. Does anyone have used Django before? Show of hands. So three people, three and a quarter people. But don't worry. So this is also now. I'm pretty good for you guys because this is also a Django crash course. So if you want to use Django, you would usually create a virtual environment first. I've already done that. So that's this tool mkvirtualenv and you give this environment a name. I've already done it. So these brackets here show you that I'm currently running a sandbox environment. And if I install any Python packages right now, they will be installed into this sandbox environment. So I have this environment now. Next step would be to actually install Django. So you do pip install Django. So in the Python world, in the JavaScript world, you know, NPM, in the Ruby world, you have like gem installed. And in Python, we do pip. Okay, this was pretty fast because I've already done it. And then Django gives you this Django admin command and you can say start project and we give it a name. I think GraphQL demo. And this will set up a folder for your GraphQL demo. Okay, let's see what's inside. There's a subfolder inside and a few files. Next thing we need to do, all right, I need to go into the settings files. So Django created the settings file for me and I need to put my IP in here. So that's, you know, ignore this. This is Django stuff. Not super important. And that should be it. If everything is fine, I should be able now to run my local development server. Let's see. Local host. No, it should be 8,000. Oh, okay. I said that I want to have this IP. It worked. So this is what you see when you just created a new Django application. All right. Okay, but this doesn't do much. So in Django, oh yeah, okay, sorry. The next step after you created a Django project is to create an app. And Django, you cut down your whole entire application into small apps. One app deals with the user profile. One app deals with your shopping cart. One app deals with your product database and so on. So we will do something like Django admin start app. And we could just call it. The app is called simple app. Very stupid name. And usually the first thing you do is you describe how the database tables of that app should look like. So I have a simple app folder here now and there's a models file inside. And I'll just copy and paste from my slides. So essentially I'm saying, I want to have a database table called message. And this should have three fields, three columns should be on my table. A user, creation date, and the message. The message is just text field, data time field, sorry, creation date. And user is a foreign key to another table. And Django already comes with a few built-in tables. So this user table here already exists and I can create a foreign key. Okay, so, and then this is typical Django stuff. You need to teach Django that this simple app thing now exists so that it knows that there's a model inside. Then Django has a very nice command called make migrations, simple app. So this will create SQL statements. So you can deploy your app on the server and it will know, oh, there's a new table. I have to create table, message with these columns and so on. And whenever you change anything in your models file, maybe I create another field later and I need to have an alter table statement, right? You run make migrations again. It detects the changes and it creates the corresponding SQL statements for you. And it creates those in a very cool way. You can even migrate backwards. So if you deployed something that is broken, you could roll back to your earlier version of your database. So this is the main reason why I use Django. So because it makes it so easy to manage your database, okay? So after I have created my migration, I will run to actually migrate. So this actually executed these alter table statements now. So now I have a real database. By default, Django creates SQLite database. You could switch that in the second settings to MySQL or Postgres easily, okay? All right. And okay, I need to do one more thing here. I'm going to sign the register from the models message, okay? So if everything went well and it never goes well, I can still go to my site and I should be able to lock into the Django admin. Okay, I have no user. So I can't lock in. So there's another command, create super user. Which I should type correctly. Create super user. Okay, let's call him admin. All right. And then we start the development server again. And now we should be able to lock in. And this is another reason why I like to use Django because it has this built-in admin interface, which is essentially like a database management interface. So I can see my tables here and I can start creating entries at the world and maybe right. And voila, I have two rows in my database. So it looks like so far everything's fine, but you don't want to learn about Django. You don't want to learn about Graphene. That's why we're here today in GraphQL. So we would do pip install Graphene Django, which I've already done. And then every time you install a third-party reusable Django app via pip, you need to teach Django that this is now part of my project. So you go back to your settings file and you say Django Graphene is now part of my project. And most apps have some specific extra settings. So in this case, we need to teach Graphene that our schema, remember? GraphQL is just a pre-relanguage and we need to set up the schema so GraphQL understands what kind of objects are available in our world. So we need to teach it where is my schema file. So we say in the GraphQL demo folder, there's going to be a file called schema, Python file, and in that file there will be something schema equals whatever. We will see that there. So this setting basically tells Graphene where it should look like, what is the entry point of my API. All right. And each of my apps also will have a schema file because we cut down our whole project in small apps. Each app has its own database tables and for each database table, you usually want to create endpoints so that you can access and write data. And you don't want to have one gigantic schema file which 5,000 lines of code. So you create sub-schema files in each of your app folders. So that will be a schema file in the simple app folder as well. And that file looks like this. All right. So we import Graphene. So this is, has anyone used Python before? Basically the guys who also use Django. And because we installed Graphene Django, we can import this Django object type here and we import the models of the own app. So this is essentially the file where we created our message table here. And so this is how it works. We say our API has a query and the query has one endpoint called All Messages. And the type, the return value of that endpoint is a list and each item in that list is a message type. Okay. What's a message type? Okay. We create this ourselves. Okay. And the good thing is it's like nicely integrated with Django. So we just say the type should be based on the message model. And that's all we have to do. So creating this schema for your huge application that might already be there is super easy. You just have to write like three lines of code per model. I mean, in the real world it will be a bit more. You might want to... You can do things like exclude fields, I think. I don't know if it's called like that, but there's something like this. And you could say maybe creation date should not be exposed to my API. I'm not allowed to query that field. But all the other fields, whenever I add another field to my model here, it will automatically be part of my message type and it will be part of my GraphQL schema. Okay. Oh, yeah. So this is the API endpoint name. This is the return value of my endpoint. And for each endpoint, we can create a result function. So it's the same name as the endpoint, but it has result underscore in front. And it's just a Python function. And you can put any kind of code here. You can do a request to the Twitter or GitHub API, fetch some data from there, or go to MongoDB or read a file from your file system. Or Django has this object relational map right here. So in Django, you never write SQL. You just say, give me all objects of message type. And this will basically be a select star from message in SQL. So it converts this nicely readable syntax here into SQL eventually. Okay. So, but you might remember that we said the endpoint is actually this file, GraphQL demo.schema.schema, right? So in a GraphQL demo folder.schema. So this is currently empty. So we put this stuff inside. And again, we have a query here, but we basically don't implement any endpoints on this query because this query is just a collection of all the other queries that we have in our ad folders. Okay. So we import the schema file from our ad folder. And this is basically an object oriented programming like multi-class inheritance. So you would just create a class that derives from all your apps. So if we had a lot of apps, we would just put them all here as parent classes of this query class. Okay. And then we create this schema variable and we call this graphene schema, whatever. Okay. Oh, yeah. Okay. So I think Django has, and Rails is quite similar, has this URL's file. Why is it not in my editor? So let me delete this part. So usually the Django URL's file by default looks like this. It only has the admin URL. And we've already been using that to create the two database entries, right? So we have to add two more lines here. So we import this GraphQL view, which comes from Django Graphene. And we hook it up here. So now under the URL GraphQL, this GraphQL view will be executed. Okay. So I think now we can test stuff. Yep. So let's try that. We restart the server. And now we go to GraphQL. Oh, it's GraphQL. Yay. And this is the cool thing now. What endpoints do I have? I press brackets, right? And press, ah, it's called All Messages. All right. And then what is the return value? Oh, okay. It knows it's the type message type. And my message model has ID, creation date, a message. And user, remember, our model has actually also a user foreign key. Is it? Yeah. This doesn't show up. Because this is another database table. And we haven't defined in our schema yet where this endpoint is and what type it is. So unless I define another type, a user type, I cannot query the user data here, okay? So, okay, when I think this is correct, I execute this query and voila, I get the two entries that I already have in my database, okay? All right. So, information. You might wonder, okay, this is pretty cool, but why do I need that on my front? How does this look like when I use it on my front? And unfortunately, nobody here has used React to S. So, this slide might be a little bit confusing now. But basically, in React, in the end, you create components for all the stuff on your website, right? Let's say a user has a job. Something on the top right side of our website, like, you know, picture, username. So this is supposed to be a component in this Java server, right? And each component must have a render function. And the render function must return html markup, okay? So we could say the user avatar is a div with an image inside. Easy, right? The problem is, what is image, right? We need to get that out of our database. So what we can do now is we could use something called Apollo, and I'll give a talk tomorrow at the talk.js meetup and pick up at the same time and describe how this will work on the front end. So you pick up something like Apollo, and it allows you to write your query, right? And usually, you use GraphQL. You write your query in GraphQL, and you copy and paste it, right, into the front end. And then you wrap your component with this decorator here, you know, GraphQL, and put this query variable into your decorator. And now, by some magic, the component has access to this, across the data. Okay, this comes from GraphQL. And it has data as the loading. So when the GraphQL request is in flight, loading is true. When the response came back, or when the request failed, loading will come false. So in our render function, you can say something like, if it's currently loading, we just, we don't return the avatar. We could return an image that shows dot, dot, dot, that is still loading, or a loading spinner, or nothing, or just the text loading, right? And once it's no longer loading, we will then return the text to data. And this is the object that we have queried. It's the endpoint of our GraphQL query, right? And then this is the field that we have queried, avatar, right? Okay, so this is, I mean, this is pretty awesome when you think about it. You task a freelancer, write me an avatar component. You don't even have to give them access to your code base or anything, right? You can give them a small rainbow that is just tied up so that it has access to your GraphQL endpoint, and then it has to write just one file, and give you back that file, and you can integrate this into your project. This component doesn't need to know anything about how the app works in total, okay? So how does an app, if you look like a React, your entire app is essentially just a collection of many, many components, okay? Like all these things, they look like HTML, right? But they are React components that we have written, right? The Azure component that we have just seen on the other slide. And we might have a main navigation component, a header component, footer component, whatever. And you just wrap this Apollo, you wrap the Apollo provider around everything. So the Apollo provider will make sure that when each of these components here tell the app what queries they want to execute, the Apollo provider collects them all and merges them together into one big query, and sends just one request to your server, takes back one response, and then this tributes the data, exactly the data the component requested back to the components, okay? And even if you have a few components that maybe one component needs user profile, but just the ID, the component just wants to know is the user currently not in. Another component needs the avatar, maybe some other component in the first name, last name. So they have similar queries, but different, but all the queries want user profile. And the Apollo provider, when it gets all the queries, it will see, all right, I have one component that wants ID, one wants avatar, one wants email. It will merge it all into essentially this, right? And then when the result comes back, it will only give down those fields to the component that has been requested by that component, okay? So, I mean, hopefully you can kind of see how this is awesome, right? Each component doesn't know anything about all the other components. And I think that's what happened with, you know, my mobile at the moment, when you just open it, it sends like 18 API requests. It catches all kinds of stuff, because on Android, usually, you have a tag notification, you have four main entries at the bottom, and they are all mounted immediately. So, same for Twitter, I'm sorry, because when you switch between two tags, it should load immediately. So, even if you just open the front page, actually for all the views, even the ones that we can't see at the moment, are already sent out, right? So, I'm sending tons and tons of HTTP requests all the time, there's a lot of overhead, right? And for example, if I have a product list view, our products, they have a massive amount of fields, like 60 or 80 fields in the database, and my API endpoint returns all the fields all the time. There's so much data, but when you think about the product list view, what do you see? Picture, name, price, three fields, right? But I'm sending 50 fields over the wire, wasting bandwidths for everyone, right? Probably even wasting performance and RAM on the machine, because all the data has to be stored somewhere, right? Check with you. Is there evaporation of the product? Actually, I don't know. I think it's done by Apollo, yeah. I thought very well, how will you handle the multiple sessions coming from different systems? Yeah, so, Apollo has this batch network interface. So if all this... Okay, I'm not 100% sure. First of all, if Apollo does the merging or if Graphia does the merging. So maybe I'm saying something wrong here, but one of the two merges everything into one big query. And logically, I think it should be a problem. And if you have components... I mean, maybe sometimes you want to send it through because the user clicks the button, right? In the beginning, when the app mounts, all the components essentially broadcast their queries at the same time, and Apollo will probably catch it all, merge it and send it to us one week. But what if a few seconds later, the user starts tapping around and it generates lots of, lots of more queries after the app is loaded, right? Apollo will put them into a queue and every 10 milliseconds, it will take them all, merge them again and send them to the server. So if you have an app that, for some reason, quickly generates tons of queries, you still say bad words because you can't say how many milliseconds you want to clean up your queue. Okay, I'm using a rainbow for the automation border. Like, where multiple users can access or you can get an automation save. But I'm getting requests from multiple users, you know, an engineer. But how we can handle the session? Second thing, if we have to change based on the user needs, how we can maintain the version... Yeah, I think this might actually show up on one of my next slides. Let me go through these. I'm wondering if you have to maintain versioning or how do you maintain it? So to quickly answer your question, when you create these functions here, the resolver functions, I will talk about mutations in a second. You have the context and this is the request. So this is like, when you think about Django, you use Django, right? You have like request.user. You can do a context like this. Django request on Django. It is a Django request on Django. So yeah, this is how, when several requests are coming in, it's the same like Django restaurant. It's really exactly the same. You can think of this like, of the resolver functions or of the mutate functions. It's essentially your Django API views. And for different things, we have to make some changes. So how do you maintain the code of versioning? Okay, this is something I haven't done yet, but it's something that they advertise on the GraphQL homepage. Yeah. So essentially, maybe later on, you add a new field on your schema. You just do it. And if you deprecate a field, you can put this deprecated thing here. So there's a way in GraphQL, when you build your schema, to say that we had this field in the past, but now it's deprecated and it shouldn't be used anymore. You access this field. Your new clients, if they send queries, still using that field, you'll get a warning message. And obviously, the actual implementation of your functions needs to be able to deal with both kinds of requests. So you could also have versioning by simply you know, when you think about the URL's pie here, we are hooking up GraphQL endpoints like this, right? You could have version one and you hook it up. Or wait, no, this doesn't work. Okay, I'm not sure about versioning. Someone created GitHub in a way where we can meet in our files version. But we don't even extract all the files from the Google. We cannot put our office coding to the Google. GitHub. Can you tell us what you can do? I'm not sure about versioning right now because the entry point is actually in the Django settings and that's just one. So I'm not sure how to do versioning. Could you not just have GraphQL on the score one? GraphQL on the score three? You mean here? We would have to have something where we can define which query class should be passed in here. But that doesn't seem to be anything. But when you Google for, you know, Django, GraphQL and versioning I have seen a GitHub issue already where people were discussing how to handle all the differences. I think, you know, people at Facebook who are mad at all the stuff, they are against versioning. They say API versioning is a bad practice and you should do it. So I think that's why they might not really care that much about it and maybe that's why GraphQL doesn't have something obvious built into it. So what's next? Okay, one more example. Actually two more, filtering and then mutations and then I'm done. So at the moment we just had a query and we just get the list of all items. What if we just want to get a subset of all items? I mean it's very common that you need to, you have an API endpoint which allows you to have get parameters to query lesser items than all items, right? So we could update our schema like this. The only changes we now import this filter connection field here and here before you might remember this was like it was saying this is a list. Now it's not just a list. Now it's a general filter connection field and we can define which columns of our database can query. So we will say we can query by a message field and it's a case-insensitive field I contain. I'm going to search for soft strings in my full text search. Okay? And the rest remains the same. The resolver function still returns simply all objects. The querying, the filtering down happens by magic. Is that enough? At least filter is now done by Adobe. No, the filter is done by Django. So in the Django world there is a very popular project called Django Filter and this allows you to create arbitrarily complicated filters and hook them up here with your endpoints. So how does this look like in GraphQL? By the way, every time when you change your schema you need to refresh this page. Ooh, this is not good. Oh yeah, I know why. So once again I start writing my query. I want messages and I want a filter and it already shows me the message field can be filtered and it's an I contains filter. So I'll choose this and then I say show me everything that starts with HE. And so usually when you create something that returns several objects you always have to have these edges and nodes and as I said I don't really understand why edges and nodes need to be used I just accept the fact that this is like it is and all I care about is that it works. So see hello world, right? And we are filtering for the substring HE or I can search for WO still returns hello world. If I just search for nothing I get all the items in the database. So filtering works. Oh okay, this is actually already my last slide. It seems like some slides I've gone missing. Where are my mutations? Didn't I just have a slide about mutations? Yeah, yeah. Oh, I deleted it. Okay, when did I do that? Okay. So filtering and querying are all nice but we want to write data. Our APIs, our rest APIs have various requests, right? So how can we do that? In our schema file everything happens in the schema file basically. We say now we have query endpoints and now we have more endpoints. We have mutation endpoints as well. So this is an endpoint that's called create message, right? And it's like of this type create message mutation. So I have to invent this create message mutation always have an input so you define what kind of data needs to be provided so that this mutation works and outputs. So this is the fields that come back. These fields are queryable in the normal way as if they were queryable endpoints. And then you write a mutate function. So here I'm basically checking if the user is logged in. If not, I create an instance of this class and I set form errors, right? One of the output fields to please log in. And if the user is logged in I just create an object in the database. This is basically the equivalent of an SQL create statement insert statement and I once again return an instance of this class and this time I don't provide form errors but I provide message the message that I have just created here and no form errors, okay? So before this can work we need to add this mutation to our main schema file so here we now have queries from all of our apps and mutations from all of our apps should be it. Oh yeah and then in Django there is some protection build in CSRF protection against hacking and so on you have to kind of disable that because all requests against this GraphQL endpoint are post requests and we don't have a CSRF token available at that moment. Okay, hopefully that works. Okay, so we're still running we need to restart my file. Okay, this looks good. So now I say I want to do a mutation and so what kind of mutations do I have? There's only one so it already provides this name createMessage and aha, it needs a field message so I mean I can only create a message if I provide some content and it returns form errors and the message itself is of a certain type so we can query all these fields once again and boom, I have just created a new item in my database. Let's just look if that's true. Now there are three. I initially only created two and some content says it's actually in a database so that's mutations. Alright, as I said at the beginning I run several companies and we are hiring if you want to do cool stuff shoot me an email. Yeah, any questions? I guess we should keep this short. Which one? The code? The site? Yeah. Yeah. Yeah. Yeah. Yeah. Yeah. Instead of giving IP numbers for like, yeah, we can. I mean when you deploy your Django backend into Cloud, you will, the domain name into that in China. Yeah, but I think this Django instance will be looked up with some domain name and you just put that into the allowable settings. Can you give allowable in IP instead of IP, I think allowable I don't have the domain here now, so... Instead of using the allow-and-wash, give-and-deem, like Martin did. Yeah, this will not work. How will it work? Yeah, I mean it doesn't work because I don't have a DNS server running that hooked up margin. As an intranet, your IP will be visible to everyone. You don't want to make your IP visible to everyone, so you want to be an Indian. You will have to be an Indian. Since you don't have an IP, you should use the name and then app name, slash app name. All you have to find is 3000, 1000... Actually, even in your intranet, won't everything be a supplement of your main company's domain? No, right? They are just false names of the machines. Yeah, I'm not sure. I'm not sure if Django can be run like that. Yeah. Any other questions? So, does it mean that I don't need Django REST framework? Yeah, you don't need Django REST framework anymore. I've just spent two years of my life building 50,000 lines of Django REST framework, and now I will delete everything and write it again. But you can actually just copy and paste your view functions over into the resolver and the mutate functions. I've started doing that. It's pretty easy. How do you test it? I'm giving another talk at the 20 lines this month, at the end of the month. You can, on media.com, you can check out the Singapore Django Notes group. And this will be a long, long, while I cover both the backend, the front-end, and a little test group as well. Testing is essentially super easy. You can just instantiate the mutation class or the query class, and then you just call the resolver functions. You put in a fake request, some fake data, and you just call these functions to move into the test. It's very easy. It's easier to test the Django REST framework, and that's already easy to test. I have a question related to the React app. Can you talk to an endpoint speeding up REST and not the draft URL? Apollo will be configured when you set up the Apollo network interface. You say the URL of the endpoint, the draft URL endpoint, and it only talks to that draft URL endpoint. But as I said, when you set up your schema and you write your query resolver functions, these can talk to any endpoint. So when you define your draft URL schema, you can't pick data from any data source. And the result is always REST. It's a JSON script. For your JSON, the schema of Android is one schema connecting to one Django class, right? Is it always a case that I can do more than one file? Well... The model.py file could have more than one table, right? It could have messages and retweets or lights or whatever. There could be many tables. And the schema will handle all these tables from the same app. It can get quite big. But usually I try to keep my apps very, very small. So each app doesn't have more than three tables or whatever. What's the occasion when you do more fragmentation? Come at the end of the month. Are you getting Rails a couple of times? Is that in your new classes? I'm sure, Django. I see a lot of REST people, a couple of REST people, so I know that there are similarities here. So I just like to imagine, in case somebody doesn't know Django, but knows Rails, so that I don't lose people in the audience. Okay. Sorry, I hope this didn't take too long. We still have some time, right? All right. Thank you.