We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

Write an API for Almost Anything (or The Amazing Power and Flexibility of Django Rest Framework)

00:00

Formal Metadata

Title
Write an API for Almost Anything (or The Amazing Power and Flexibility of Django Rest Framework)
Title of Series
Part Number
20
Number of Parts
48
Author
Contributors
License
CC Attribution - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Identifiers
Publisher
Release Date
Language

Content Metadata

Subject Area
Genre
Abstract
This talk will feature a few off-the-beaten-path applications of APIs. Since the combination of Django and DRF makes it so easy to get a simple API running, it becomes a very powerful, flexible, and expandable tool for a variety of uses. The only thing these applications may have in common is their need to share data across the web. Whether you have not yet tested the waters of Django Rest Framework or you are a DRF veteran, this talk will inspire you to think both big and small when considering its potential uses.
Power (physics)Software frameworkSoftware developerLocal GroupWeb pageInterface (computing)Computer programmingComputer programCodeSoftwareBroadcast programmingClient (computing)InformationFunction (mathematics)Scripting languageGame theoryAerodynamicsJava appletContext awarenessBuildingView (database)Endliche ModelltheorieComputer fileContext awarenessPower (physics)Game controllerInformationDatabaseWeb pageInstance (computer science)BuildingElectronic mailing listCodeClient (computing)Software frameworkTemplate (C++)Single-precision floating-point formatJava appletSerial portQuicksortResultantFlow separationEndliche ModelltheorieScripting languageCartesian coordinate systemLink (knot theory)File formatGreatest elementSlide ruleView (database)AverageMultiplication signAreaGenderSelf-organizationGroup actionInterface (computing)Scheduling (computing)Game theorySet (mathematics)Medical imagingSound effectMobile appUniform resource locatorComputer programmingServer (computing)CASE <Informatik>Query languageDifferent (Kate Ryan album)Router (computing)Term (mathematics)Field (computer science)Physical systemData structureFunctional (mathematics)PlanningWeb-DesignerPresentation of a groupMultiplicationState of matterSocial classArithmetic meanWeb 2.0Perspective (visual)WordSubsetSoftware developerReal numberType theoryWeb applicationComplex (psychology)Object (grammar)Meta elementFront and back endsProof theoryDirection (geometry)Reading (process)Computer animation
Uniform resource locatorRouter (computing)BuildingSoftware frameworkUniform resource locatorRouter (computing)Data structureNamespaceEndliche ModelltheorieLine (geometry)Functional (mathematics)View (database)Medical imagingDefault (computer science)Different (Kate Ryan album)CASE <Informatik>Gender
Operations researchReading (process)Software development kitInformationComputer configurationAuthenticationView (database)Set (mathematics)Group actionUsabilityUniform resource locatorMilitary operationParameter (computer programming)File formatSoftware frameworkSoftware frameworkInstance (computer science)Data structurePatch (Unix)Field (computer science)Endliche ModelltheorieParameter (computer programming)Template (C++)MathematicsOperator (mathematics)Group actionSerial portLevel (video gaming)Software developerDifferent (Kate Ryan album)View (database)AuthenticationFile formatElectronic mailing listLink (knot theory)Information1 (number)Line (geometry)NamespaceComputer configurationLatent heatSampling (statistics)Uniform resource locatorPower (physics)Functional (mathematics)Cartesian coordinate systemNumberComa BerenicesReading (process)Mobile appUsabilitySelf-organizationGoodness of fitSound effectGenderXML
InformationSoftware testingFunction (mathematics)Sample (statistics)Local GroupTwitterSoftware frameworkSoftware testingAuthenticationDatabaseRandomizationDifferent (Kate Ryan album)Dependent and independent variablesObject (grammar)CASE <Informatik>Direction (geometry)Functional (mathematics)Reverse engineeringAttribute grammarEndliche ModelltheoriePoint (geometry)View (database)TwitterUniform resource locatorProjective planeSheaf (mathematics)Control flowMathematicsLengthSoftwareInformationSoftware developerInclusion mapSoftware frameworkCodeLink (knot theory)MultilaterationSlide ruleElectronic mailing listEntire functionCartesian coordinate systemScheduling (computing)File formatIndividualsoftwareNamespaceInstance (computer science)GenderSampling (statistics)AreaSet (mathematics)Regular graphSummierbarkeitEqualiser (mathematics)Sound effectGroup actionXMLUML
Projective planeConnected spaceQuery languageType theoryFormal languageQuicksortSerial portSource codeEndliche ModelltheorieCASE <Informatik>Software frameworkAuthenticationRevision controlGroup actionSet (mathematics)SpacetimeMobile appFactory (trading post)Multiplication signUniform resource locatorOrder (biology)Absolute valueDirection (geometry)Cartesian coordinate systemTheoremInstance (computer science)IntegerSpectrum (functional analysis)MereologyFormal grammarFunctional (mathematics)Table (information)Parameter (computer programming)AuthorizationPoint (geometry)Information privacyWeb browserLecture/ConferenceMeeting/Interview
Coma BerenicesXML
Transcript: English(auto-generated)
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 PyLadies group in our area, and most importantly for this talk, I am a builder and user of APIs. If you'd like 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, don't worry, you can get it at the end. So, we should 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 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. Once you've got an API in place, that gives you the ability when suddenly a
customer has a need right now, they'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, well, it did a lot of things, it 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 Django 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 backend so that the frontend, the user experience,
the gameplay could all be done 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 Django 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 Django 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 Django REST Framework. Django REST Framework sits nicely on top of existing Django code and has a very
thorough feature set. Cactus Group uses Django 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 Django REST Framework API. At the bottom here, you've got your existing Django models, which, you know,
Django 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 Django REST Framework that is just going to take your model information and parse it into a format going in both directions that the viewset can work with. Viewset 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 viewset 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 URLs. So where do we put these things? This is my convention. I like to have a file called, this is all within my app, within my Django app. I like to have a file called serializers.py that has my serializers in it.
I like to put my viewsets directly into views.py. If you want separation, if you're still using Django templates and you want separation, you could also put this into a file called api.py. It would work just fine that way too. And then the router is going to go right into your URLs.py. This can be inside the app or it can be your global URLs.py 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 going to import our model for our models file. We're going to create a serializer that's just subclassing the Django 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 up a step in our ladder to the viewset. So we're going to import that viewset. 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 viewset from Django rest 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 viewsets for different types of, you know, different subsets of your data if you wanted to have different functionality. But in this example, we're just going to use all of it. And then you tell it what serializer class. That's just going to 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 Django URLs code. I have a convention that I like to import the views as a name-spaced things because if you start putting all this, especially if you put this in a global URLs 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 Django rest framework router structure. And then we're going to register our model with this. So, router.register.
We're going to give it a name-space. 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 viewset is. Django rest framework will take care of parsing the different URLs and the different methods that need to happen here. And then we just have to include our router.urls.
If you had other models, other viewsets 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 auth, which gives you access to the Django rest framework built in browsable API.
So you can click around and see what the functionality of your API is for learning the structure. Alright, 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 Django rest 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 detail view, we're going to use a get. 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 going to assume those are the ones that changed, and everything else I'm just going to leave the way it was. And then finally, delete uses the HTTP delete method. There are more HTTP 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 urls.py here so that 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 get HTTP request to myapp.com slash my model,
it's going to give me a list of the instances. It's going to be based on that serializer. If I do a post to that same URL, just app.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. This is not an 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 Jenga REST framework's documentation, which I put a link to here. So what if you don't want 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 Django 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 Jenga REST framework.
You also can do just read-only view sets. Django 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 set level. And all of this information, again, Django 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's gonna 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 be highly variable
because this API is gonna be constructed the same way over and over again. You'll need to give the URL and HTTP 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. Django REST framework will do this for you too.
So you can just create a docs URL in your urls.py and do include docs URLs imported straight from Django REST framework, and it will create your API documentation at that URL, and you are off and 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 that'll catch 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 Django REST framework. It is built on the Django test case and is very, very similar. You can also use the Django test case directly
if you don't wanna try to learn something new. There's very little that's different between this and if you use the Django 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 gonna give me that base URL.
This is the namespace that Django REST framework gives to it, just as if you had put a name equals in a regular URL. And then I'm just gonna create some instances for the purposes of my testing. So I'm just gonna run through and create a couple of instances.
And then I've got a test list view here. So now I'm gonna go do a self.client.get just like I would in regular Django test case. Point at the URL, tell it the format is JSON because this is all JSON. And then I'm gonna do, I'm gonna assert equal that the response status code is a 200
because this is a get. So I'm expecting, I'm not creating anything. It should just give me a 200 back. And then I'm gonna 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 Django test case. That's just gonna 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. 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 wanna 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.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 Django application you already had. So your homework is to think about what Django projects do you have live? What Django 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 you'd be 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 gonna 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 wanna build out because only two people are ever gonna use it,
somebody might use it via an API. They'll go 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. Django REST framework documentation, that example project I mentioned. These slides, Cactus Group and my own Twitter. As I walk to a question, I'll ask one of my own.
I noticed you were talking about the browsability. Is it API-Auth? Does that mean that there's authentication implied on top of it or? Yeah, you can authenticate. I think that if there's not an authentication layer that you can go directly to the API URLs.
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. So I wasn't actually 100% sure on that. Yes, thank you. Nice talk. 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? So you could version if you wanted to. I would probably not recommend it because you're gonna want it to stay current with your app and so by building it this way it's just gonna 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 wanna version it and then in that case that ability to register things
would give you that ability to transition to a new set of URLs. All right, you talked about authentication. What about authorization? So if I have access to the GET, you know, do a GET and I know my user ID is one, I start poking around and look at two and three and four and five.
Yeah, so again, you can look at the logged in user. You know, you have access to request.user just like you would in any other Django request and you can have a method in that viewset 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. Hi, does Django REST framework play well with data sources that aren't the ORM? Oh, that's a good question. I think it would.
Assuming you create something to 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 pass it into the viewset just as if it were any other serialized data.
So I think 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? 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 Django authentication.
If a model is gonna throw a 403 when a user requests a particular instance, then Django rest framework will do the same thing as long as you've got the authentication turned on. Hey there. Two parts, first the comment then a question. Okay, fine, I'm just gonna ignore that.
Your talk was awesome. Out of all of them, I really look 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 Django API projects that are using channels because I feel they both would work well together?
Thanks again. 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 they would play well together. Thanks again. Are there any, is there any support for the GraphXL 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 thought about it or does it already support something like GraphXL or the more advanced querying type API? So anything you can get your application to generate,
you can then expose through the API. It'll be 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. All right, thank you very much. Absolutely, thank you.
Thank you.