 Welcome to DjangoCon and good morning. So this talk is a novice level talk and my purpose is for novices to get familiar with the terminology of APIs. And for me to give them the confidence to explore Django REST framework on their own is REST. What is RESTful kind of gets talked about a lot. Really it's just an architecture. And for the purpose of web APIs, it has a few properties that define a RESTful API. It has to be stateless. So, you know, the client doesn't have to maintain any sort of knowledge about the server. Each request is kind of made as if it were fresh. It supports common HTTP methods such as, actually we'll see some on the next slide. And it returns internet media types like JSON or XML. So HTTP verbs, these are the five of them. We have a post get, put, patch and delete. It's like crime, sort of, not quite. So we use them to perform operations on different endpoints. And our endpoints are gonna look kind of like this. So that first endpoint, if we call a get on it, it will return a collection of all users. The second endpoint, we wanna pass it an ID and it will return, if we call a get on it, it will return the single user at that ID. So, some of the other HTTP verbs, how would they look like if we called them on these endpoints? If we called a post on our first endpoint, it would create a new user. If we called a delete on an endpoint with just an ID, it would delete that single user. If we called delete on our user's collection, it would delete all the users. So, not very good. And here are some common HTTP response codes that you'll probably see when you're using your API. So, 200 is okay, 201, if you call a post on an endpoint and 201 is returned, that means that resource was created. 401 is not authorized. So, the endpoint requires some sort of authentication like a token and you did not provide it. For a four common one, the server did not find the resource that you requested and 500 is a server error. So, idempotency, it's a hard to pronounce word. What it means is that the operation produces the same result no matter how many times it is repeated. So, put and delete are idempotent. Well, get is a safe method. It might not return the same result every time, but by calling it, you're not modifying any resource. You're knowing that the server isn't, you know, kind of doing anything funky to mess with that object that you're trying to get. So, here is where DRF comes in. DRF is Django REST framework and it makes API creation really, really easy. So, serializers can kind of be thought of as Django forms. They're a guide to representing your data over the wire. You're telling DRF how you want that data to look. So, here we have a model of a tweet. It's very simple. We have a foreign key to user. We have some text. The maximum length is 140 characters. And we have a timestamp. So, to represent that data, we're gonna wanna make a serializer for this model. So, we're gonna tell our serializer that the user comes from the source field user. And in the meta is where we define which model we're trying to serialize and what fields on that model we're trying to represent. Non-model serializers are also available. You kind of have a bunch of random data and you wanna create an endpoint out of it. You can create a serializer, but that nice fields that won't be available to you, you'll actually have to define every serializer one by one. So, when we pass our data through our serializer, this is what our result will look like. If we configure DRF to send back JSON responses, which are the default, can also pass back XML. And that's just a simple setting. You don't really have to change any of your code. So, DRF supports really great validation. And here's what a field validator looks like. So, an interesting thing to know is that by creating a method called validate underscore text, it automatically knows that this validator is for that text attribute. There's no configuration here, it's just kind of a naming convention. So, here we're getting our source attribute out of the list of values and we're checking to see if the length of it is less than five. If it is, we're gonna send back a validation error that says the text is too short, we're gonna get back an error response in our API. Other kinds of validators that are available is valid. If you add that method to your serializer, you can actually validate a combination of attributes. For example, if you have a start date and an end date, you would, and you wanna make sure that your end date isn't before your start date, you would put that validation logic in your is valid method. And if you wanna make sure that your serializer is valid, you can call that method on it, pretty similar to a Django form. So, permissions. Let's say we only wanna let authenticated users see our list of tweets. So, is authenticated is actually a built-in permission in Django REST framework and does what it says, it only allows authenticated users to hit that endpoint. Another built-in one is admin user and it checks to see if the user is actually a staff member or not. Creating your own permissions are actually very easy. Let's say we only want the author of the tweet to be able to edit it. So, we create our own permission, we base it off base permission and we create a method called has object permission. So, before our endpoint is hit, that object is passed into this permission method and we check if our method is in the safe methods such as get, go ahead, let them see it. If they're trying to call something destructive, like a delete, make sure that the object user is the same as the request user. So, views are a really interesting topic in DRF. The easiest one to kind of get a grip on is called a view set. Here's an example of a model view set. So, we only have to define a few simple variables to be able to use this endpoint. We have a query set. So, that's how do we get a collection of the items that we're trying to view. We define our serializer and we define a list of permission classes. So, you can provide a set as long as you like for each of your endpoints. We can also define a handy pre-save method. So, that gets called before the object is saved to the database and we want the user of our tweet to be saved as the request user. So, the model view set is kind of the whole shebang in one. Behind the scenes, it supports all of the operations on an endpoint. So, you can get one tweet by an ID. You can get the collection of tweets. You can delete, you can modify and that's kind of all given to you by using this class. It's really handy. So, model view sets are awesome when you're working with models but sometimes you have to break things down a little bit more. So, General Us Framework provides us generic views. API View is the base class. Kind of takes care of all the routing. So, if you're calling get, it'll call the get method. And mixins provide common operations. So, and there's some generic views that are provided for us that kind of have a common combination of mixins. For example, if you're only supporting an endpoint that has a list of objects, then you would call the, I'm sorry, you would use the list create API View and it would support get and post for you and you would kind of have to fill in those details. Request and Django Us Framework actually look pretty similar to many of the methods that we're used to seeing. So, if you guys have used Django forms, you're used to seeing a request.post and that's the data that comes in when a user submits your form. Request.data is kind of similar. It provides all the fields that were submitted to the API, along with our values. Handles the data types we specified. I pretty much exclusively use JSON, but some of you might like XML. And responses are also kind of similar, but not really. So, Django Request Framework responses are actually completely unrundered. You're getting a bunch of data back and it's up to you to figure out how you wanna consume it. So, maybe you're using jQuery on your front end to call this end point. Maybe you're using Angular or another JavaScript framework, but what's going on behind the scenes when you want a response back, if you're using a serializer is your query set, those tweets are being passed into the serializer. The serializer does its work and spits out that JSON representation. And then you call response with that serializer data. By calling response with no status code, you're actually just sending back a 200. If you wanted a processor request with your serializer, you would pass that request data into your serializer and then call serializer.isvalid before actually performing the save. Otherwise terrible things happen. So, let's talk a little bit about routing. Viewset routing is absolutely the simplest. So, we have what's called the default router and we register our view sets with it. The nice thing about using a default router is we can pass all sorts of configurations to it. For example, if you don't care about appending trailing slashes, that's a property that you can pass into default router on instantiation. So, when you register your view sets, all you need to do is include the router URLs in your URL patterns. And what that gives you is the whole shebang. You have tweets multiple, end point, you have a single tweet end point and then you support all the operations on those end points as well to get the post delete kind of with just this. So, without view sets, you're gonna be setting up your routing in a default way. So, you would create a name for your view and then register each URL pattern. The Brasable API is really one of the strongest features of the Django REST framework. So, it gives you a API end point that you can kind of hit and instead of getting just a vanilla JSON response, you'll get this kind of interactive page and you can see all the methods that are available on your end point via that get. You can hit it, you can provide data to it. I think we actually have time for a little bit of a demo. So, let's see, make sure my server is running. I was messing with my code, so no. Sorry about that guys. It's kind of what happens when you do live demos when you're talking, right? Something is always broken. So, here's an example of the raw data that you can pass in. You'll have to make sure that the data that you're passing in is valid JSON and then it matches the fields in your serializer or Django REST framework provides this handy dandy HTML form. So, it provides the correct input box for the data you're trying to pass in. Unit testing, everyone loves the testing go. It's important. So, in our past V slides, we defined this field validator that tests and makes sure that the tweet that someone is trying to submit is more than five characters or it's invalid. So, here we're creating a test for that validator. Let's walk through it one by one and see what's going on. So, we define our API client, which again has many useful methods available for us for unit testing. And here we're logging in. We're authenticating our request. So, if we didn't pass that in and we have an authentication permission, then we would get a 401 back, not authorized. We're getting the URL for our endpoint. We're making up some test data. So, this will print out four Xs and we're posting to that URL to create a new tweet. And we assume an error message. So, we wanna assert that the status code is 400. That means bad request, your data isn't valid. We wanna ensure that the error message is the same one that we provided in that validation exception. So, I've been using it pretty extensively for the past few months and definitely have some feedback. So, the best place to use it is new projects. You don't really have to code for the framework or around the framework. You can use some of the really powerful tools that are available, such as those view sets. You have clean models, not a ton of interdependent validation going on. In that case, it's really just excellent. It saves you so much time. So, when not to use it, legacy Django is out there. If you have a ton of complex models, interdependent validations, if you're trying to save non-model fields in your endpoints, things really kind of get tricky. You don't get to use that nice view set. You kind of have to break out and use those generic view sets and customize your code to deal with some of these complexities. So, doesn't mean you shouldn't go for it, but really there might be hurdles. On the bright side though, Django S Framework 3 is on the horizon and apparently they're gonna be fixing some of these issues that I've had and redoing the serializers completely. So, don't discount it, keep an eye out for it, but just prepare for some issues. So, next steps for you guys, PIP install Django Rust Framework. The documentation is really good. The tutorial is very thorough. Hopefully, I've familiarized you with some of the terminology that you'll be seeing. And that is it for me. Thanks guys. Thanks so much, Nina. I think we do actually have time for perhaps one or maybe two unbelievably brief questions. So, if somebody has a snappy one. Thanks for great talk, Nina. I just wanted to quickly ask you. Is there any sort of particular pattern you think that doesn't work with models with APIs in general, like sort of a passive-conversed relationships or sort of foreign keys? What would your advice to new programmers on how to handle that kind of sort of more complex model structure? I've been able to do it before a few hiccups. It definitely still helps to have those built-in things, like those generic API views. You don't have to write a bunch of code to be like, when this request is get, do this. And the API browser has been such a powerful and helpful tool that it's still worthwhile. Kind of exploring it even for more complex data models. Thank you. Sure. I was wondering, you were talking about like having clean models and if you didn't really, it was kind of a tough fit or if you had old code, it was a tough fit. I was wondering if you thought that in some ways, because it's something that I've looked at and I actually have two of those issues a little bit with older code base. But I was wondering if you thought it was able to, it was practical to break out certain components like the serializers, if you thought that was practical or if it's actually kind of pretty tangled up together if you had any, if that question sort of made sense. If it's possible to sort of use some components, even if you can't use the whole thing. I actually tackled that problem with a very complex model both ways with a serializer and without a serializer. Using the serializer required a hack kind of out of the scope of this talk, but I'm happy to talk to you about it afterwards. And it really did provide some nice things. For example, field level validation, like if I said my serializer only accepts 140 characters instead of the model, it would kind of throw back that correct error. Whereas if I didn't use the serializer, I'd have to do all that kind of plumbing myself. All right, Nina, thank you again. Thank you guys.