speaker 1: All right. Can everybody hear me? Okay, great. Okay. So I'm going to talk about writing apis for almost anything. I am, as was just said, a web developer at cactus group. I am one of the organizers of the piladies group in our area. And most importantly for this talk, I am a builder and user of apis. If youlike to follow along with my slides, the link is here, and I will also have that link again at the end of the presentation. So if you just want it for reference later or you can get . speaker 2: it at the end. So we should . speaker 1: probably start by defining our terms. What exactly is an api? Well, it stands for application programming interface. But to be perfectly honest, that probably doesn't give you any more information than you had before. More importantly, it is code that lets two software programs communicate with each other. That's the really key piece about what an api is, and that's what makes it both powerful and useful. So we like apis because they give us flexibility. Once you've got an api in place, you've got access to all those basic functions, reading your data, updating your data, etc., without the entire structure of what you expect the workflow to be. And so that gives you flexibility to be able to do different kinds of things. It also gives you more access. Obviously, we think of apis largely in terms of users being able to access directly. But you also can use an api internally and make it not even expose it to the outside world, but use it with two different pieces of code on one server or on two different servers that just talk to each other so that you have better access to your own systems. And you can also use this for future proofing if once you've got an api in place that gives you the ability when suddenly a customer has a need right now, that you've got to do something a little different, you've got an api in place that gives you that flexibility, again, makes it easier to implement new things without as much complexity. So to give you an example of when an api might come in handy, I have a friend, this is a real story massage therapist who needed his schedule information to be shareable without the client information attached. So basically, what times he had appointments without the client names? His scheduling software, while I did a lot of things, didn't do this, but it did have an api. So we were able to put together a small script that can pull that schedule information via that api, strip out the client information, and then post that appointment information up to a shareable calendar. The api, in other words, made it possible for him to create an otherwise non existent feature from the perspective of a user, not a developer. You also can use apis for non web applications. I'll just mention this briefly. We often think of Jango as being a web framework, and that is its primary purpose. But that doesn't mean that its power and flexibility is limited to the web. As an example, I gave a talk at a game conference about how this could be used to create a game back end so that the front end, the user experience, the gameplay could all be without having to worry about the shared state of the game for multiplayer types of applications. And you can see that code up on my GitHub here. You also can use apis for internal separation of code within your own applications. Modern applications are heavily reliant on JavaScript to be highly interactive and responsive. And so that requires JavaScript. You can use an api to separate your Jango code from your JavaScript code, which results in having cleaner code because you don't have that all tangled together in spaghetti code. And it also makes it easier to use a lot of JavaScript frameworks that are going to often be built around building a single page app, which isn't quite the way Jango templates work. So if you have your code built with an api, then you can have that JavaScript framework built as a single page app, and it can retrieve the data and context that it needs with simple api requests. And again, this can be on the same server. So you're not really dealing with any sort of latency here. All right, so how do we do this? There are a lot of ways to build an api. There are a lot of packages available to do it. This talk is going to focus on Jango rest framework. Jango rest framework sits nicely on top of existing Jango code and has a very thorough feature set. Cactus group uses Jango rest framework all the time. We like it enough. We actually even sponsor it. Let me show you why. So here's the anatomy of a Jango rest framework api at the bottom here you've got your existing Jango models, which Jango takes care of, your database, all that sort of thing. On top of that, the next layer you've got is your serializer. This is a piece of Jango rest framework that is just going to take your model information and parse it into a format going in both directions that the view set can work with. View set is the next layer here, and that is what handles. Okay, am I creating a new instance? Am I updating an instance? Do you just want a list of the instances? The view set handles figuring out what information needs to either come out of the database or go into the database and control that. And then the last thing on top of that is the router, and that's what handles the actual access via the url's. So where do we put these things? This is my convention. I like to have a file called within my app, within my Jango app. I like to have a file called serializers stpi that has my serializers in it. I like to put my view sets directly into view pi if you want separation. If you're still using Jango templates and you want separation, you could also put this into a file called api pi. It would work just fine that way too. And then the router is going to go right into your url pi. This can be inside the app or it can be your global url pi either way. All right, so let's start at the bottom and talk about the serializer. So this is the serializer. This is it. So we're going to import serializers from rest framework. We're gonna to import our model from our models file. We're gonna to create a serializer that's just subclassing the Genger rest framework model serializer. Give it a meta class, tell it what the model is and tell it what fields we want included. Any field that's not listed here, the api is just going to ignore. So if you have private internal fields, you can leave them out of the serializer and they won't be exposed. Now let's move a step in our ladder to the view set. So we're going to import that view set. We're going to import our model again, and we're going to import that serializer that we just created. Then we're going to, again, subclass the model view set from gender s framework. Tell it what our query set is. In this case, I'm just using all of the objects that I have for my model. You could do different view sets for different types of different subsets of your data if you wanted to have different functionality. But in this example, we're just gonna na use all of it. And then you tell it what serializer class that's just going na be your serializer that you created. And finally, let's put the router on top. And this is going to nest just right within your existing Jango url's code. I have a convention that I like to import the views as a name based ed things. Because if you start putting all this, especially if you put this in a global url's file, but either way, it makes it much easier to read. When you look down here, we're going to define our router, router equals routers, default router. That's just going to initialize it using the gen gi rest framework router structure. And then we're going to register our model with this at rourouter register. We're going to give it a name, espace. I'm just giving it the name of the model in this case, but it can be anything. And then you're going to tell it where the view set is. Jangeras framework will take care of parsing the different url's and the different methods that need to happen here. And then we just have to include our router dot url's. If you had other models, other view sets that you were importing, you would just need an extra register line for each of those. The rest of this would stay the same way. And at the very bottom here, I've got one other thing that's handy to have on there is the api off, which gives you access to the gengerres framework built in browsable api. So you can click around and see what the functionality of your api is for learning the structure all so when we're accessing our api, api structure is typically done using the crud acronym create, read, update and delete. And we're going to use specific http methods so that jgar s framework knows what we're trying to accomplish. So when we're trying to create an instance, we're going to do a post. When we're trying to read, either get a list or get a detaview, we're going to use a git for update. We're going to use either a put or a patch. The big difference between these is put is going to expect all of the fields, just as if you were doing a post, whereas patch will just take whatever fields you gave me. I'm gonna na assume those are the ones that change. And everything else, I'm just gonna na leave the way it was. And then finally, delete uses the httttp delete method. There are more htttp methods than this, but these are all you need to know about for this particular functionality. So just to give you a few examples, I'm just reprinting our register line from the url step I here so you can reference it. The only thing that we really need to reference here is the my model namespace that we gave it. So this is going to translate into if I do a ghttp request to my app com slash my model, it's going to give me a list of the instances, and it's going to be based on that serializer. If I do a post to that same url just app dot com slash my model, then it's going to create a new instance. It's going to expect me to be passing the data to create a new instance. If I do a get to my model slash an ID number, then it's going to get me the details for the instance that has that ID. If I do a delete to that same detail url, then it's going to delete that instance. These are not, this is not exhaustive list of the ways you can do it. It's just a sample to give you an idea of how this works, more detail can be found at Jander rest frameworks documentation. Which I put a link to here. speaker 2: So what if you don't want . speaker 1: your users doing all this? Maybe you don't want your users directly having access to delete instances? Well, there's different options. You can either put a layer of authentication on top. That layer of authentication will use the same authentication as your Jango user model. So if you want to restrict access, you can restrict access in exactly the same way. You've already got it restricted on your templates and so on. So whatever a user doesn't have access to, normally they won't have access to through Jango rest framework. You also can just read only view sets. Jango has built in read only view sets. So if you want to let people access information but not update anything or delete anything, that's a one line change from what I've just showed you. And you can also restrict specific actions. So maybe the only thing you don't want users doing is deleting. You can just restrict that specific action at the view wset level. And all of this information, again, gender rest framework has fantastic documentation about how to customize all these different things. But I'm just trying to give you an idea of what the power of this is. Speaking of documentation, your api will need documentation because nobody Bois going to be able to make use of it if they don't have any documentation of it. This is key to usability, even if you're only using it internally. Your developers will thank you if you have documentation. But there's a very specific structure that we need here. This isn't gonna to be highly variable because this api is going to be constructed the same way over and over again. You'll need to give the url and hdp method what operation is performed when you hit that url with that method, what parameters it expects to receive, and what data format will be returned. Jgerus framework will . speaker 2: do this for you too. speaker 1: So you can just create a docs url in your urls pi and do include docs url's imported straight from Jangar rest framework, and it will create your api documentation at that url. And you are off running. I hope that you also are sitting here thinking, but how will I test this? Because we all should be testing our code, and that also is easy with this. So automated tests give you the ability to just set it and forget it. They get run when you run your regular test suite. And if something breaks for some reason, then thatcatch it. Test failures can also highlight changes that should be reflected in documentation if you have done any custom documentation. So here's some sample tests. In this case, I'm using the api test case that comes with Jango rest framework. It is built on the Jango test case and is very, very similar. You can also use the Jango test case directly if you don't want to try to learn something new. There's very little that's different from between this and if you use the Jango test case directly. So I have a setup function here where I define my url. I'm doing a reverse on my model dash list, and that's going to give me that base url. This is the namespace that Janger rest framework gives to it, just as if you had put a name equals in a regular url. And then I'm just gonna to create some instances for the purposes of my testing. So I'm just gonna to run through and create a couple of instances, and then I've got a test list view here. So now I'm gonna to go do itself dot client dot get just like I would in regular Jango test case point at the url, tell the format is Jason because this is all Jason. And then I'm gonna to do, I'm gonna to serequal that the response status code is a 200 because this is a yet. So I'm expecting, I'm not creating anything. It should just give me a 200 back c and then I'm gonna to assert that the length of response data is three. And response data is one of those little things that you get with the rest framework test case that you don't get directly with the Janger test case. That's just going to pull out the data section specifically from the response. So I can just make sure that there are three objects in that response data. You can also check and make sure that the data is looking like you would expect it to look. But I wanted to keep things simple. For purposes of this, a couple more samples. Testing creation is very similar. In this case, I'm checking to make sure I get a 201 because it will have created an object. Again, you can also check to make sure that the attributes are what you expect at this point. And then testing the detail view. I'm showing this primarily because I want to show you how I would affect that url. So I'm just grabbing any one of the objects I created, just grabbing the first one that comes out of the database at random, and then creating my detail url by slapping that ID onto the end of it. And then I can do the exact same thing. Just do a self client dot, get at what's now my detail url, and again, make sure that I get a 200 response. All right. So that is it. We have just built an entire api on top of presumably some Jango application you already had. So your homework is to think about what Jango projects do you have live, what Jango projects do you have in development that you could add an api layer to do? They have public information. That is a fantastic place for an api because yoube amazed what people can pull out of public information. They have collections of user data. Those users might want access to that data in different ways. Think back to that massage therapist example. He wanted access to the data in a way that the original developers didn't anticipate. If you can't think of a use for your data in an api format, don't worry, your users will. And this is going na give you a competitive advantage because again, think back to that massage therapist example. If he was using a scheduling software that didn't have an api, but he needed this functionality, here's a motivation for him to switch to one that does have an api. So he can have this functionality that not many people need, but he needs it enough that he's willing to pay for a custom software solution. So those little tiny edge cases that you don't want to build out because only two people are ever going to use it, somebody might use it via an api theygo to the effort of building it, and then you have that kind of lock in going on because you've got that api that makes that possible. So at this point, I will take questions. I've got some resources here. Again, as promised, the slide link is in the middle. If you want to look that up for reference later, Janger rest framework documentation, that example project I mentioned, these slides, cactus group and my own Twitter. speaker 3: As I walk to a question, I'll ask one of my own. I noticed you were talking about the browsability. Is that api dash off? Does that mean that there's authentication implied on . speaker 1: top of it or so Yeah, you can authenticate. I think that if there's not an authentication layer that you can go directly to the api url's. I have all of the cases when I've used the browsable api. It's been on one that I did have an authentication layer on it. speaker 4: So I wasn't actually 100% sure on that. Yes, thank you. Nice talk. I my question is, do you version your url spaces for these exported apis typically? Or do you have a use case for that or any experience with versioning? speaker 1: So you could version if you wanted to. I would probably not recommend it because you're going to want it to stay current with your app. And so by building it this way, it's just going to continuously track with your app. The only time I would try to version it is if there was a model that I was going to deprecate or something. And then by versioning, I could indicate, okay, this particular url set is going to go away and then therefore transition. That's the only use case I can think of offhand when you might want to version it. And then in that case, that ability to register things would give you that ability to transition to a new set of url's. speaker 5: All right, you talked about authentication. What about authorization? So if I have access to the get, you know do we get and I know my user ID is one, I start poking around and look at two and 3D . speaker 1: and four in Yeah. So again, you you can look at the Log In User. You you have access to request user just like you would in any other Jani request and you can have a method in that view set that says, you know if request user does not equal the user that's being asked for, then permission denied. That is very easy to implement using that authorization. speaker 6: Hi. Does Janger rest framework play well with data sources that aren't the orm? Oh. speaker 1: that's a good question. I think it would, assuming you create something a stand in for the serializer, there is plenty of customization that you can do on the serializer. So I would think that, that would be how I would do it, would be to customize the serializer to work with that data source, and then that would PaaS it into the view set just as if it were any other serialized data. So I think . speaker 6: that's how I would do it. Have you ever regretted exposing an api to users because they found something you really didn't want them to find or because they bombarded you with annoying questions? speaker 1: I have not ever had that experience. I will say that in every case where authentication mattered for any of the data, I applied the authentication on the api as well. And I think that's just solid data safety in general. If it's not public data, I would have that authentication layer. And again, it borrows off of the existing Jango authentication. If a model is going na throw a 403 when a user requests a particular instance, then Janger reframework will do the same thing as long as you've . speaker 7: got the authentication turned on. Hey, there two parts. First a comment, then a question. No. Okay, fine. I'm just going to ignore that your talk was awesome. Out of all them, I've really looked forward to yours and you absolutely killed it. My interest started on my new project. I'm working with an api incorporating with a jQuery data table. Anyway, as for the question, do you know any Jango api projects that are using channels because I feel they both would work well together. Thanks again. speaker 1: Hmm, so I have not actually worked with channels myself. It's something that's interesting, but I haven't had a chance to play with it, so I can't really speak to that. I don't think it would work well though because channels are designed to maintain that open connection and the api is inherently asynchronous. So I don't think that . speaker 8: they would play well together. Thanks again. Are there any is there any support for the is it like graphics l or some of the query type languages that are built on top of you know api, the sort of vanilla api with crud has drf? Have they have they thought about it or does it already support something like graph excel or the more advanced querying type api? So anything . speaker 1: you can get your application to generate, you can then expose through the api itbe using a custom serializer generally, again, if it's not directly from a model, but I've done this. I've actually built an api endpoint that gave you generated data as opposed to the direct original data. So by using that custom serializer functionality, you can get just about anything to go through your api portal. Thanks for the great talk. Do you recommend something like mixer or factory boy in order to generate better models for your testing? Yes, absolutely. I usually use factory boy. I did just direct creation of models in this case just because it was simpler. But Yeah, I usually use factory boy to create instances. speaker 3: All right. speaker 1: Thank you very much. Absolutely. Thank you. speaker 2: The.