Monitor performance issues & errors in your code

#284: Modern and fast APIs with FastAPI Transcript

Recorded on Thursday, Jul 23, 2020.

00:00 Python three is eclipsed the old constraints of Python two and the web frameworks that adopted them. We've seen a big jump in the new frameworks appearing on the scene taking full advantage of things like taipans, async, await and more. No framework has done this more successfully than fast API recently. That's why we're here with the creator of fast API Sebastian Ramirez to dive into this exciting new Python web framework. This is talk Python to me, Episode 284, recorded July 23 2020.

00:40 Welcome to talk Python to me, a weekly podcast on Python, the language, the libraries, the ecosystem, and the personalities. This is your host, Michael Kennedy. Follow me on Twitter where I'm at m Kennedy. Keep up with the show and listen to past episodes at talk python.fm and follow the show on Twitter via at talk Python. This episode is brought to you by linode. And us pythons async. And parallel programming support is highly underrated. Have you shied away from the amazing new async and await keywords because you've heard it's way too complicated or that it's just not worth the effort. But the right workloads 100 times speed up is totally possible with minor changes to your code. But you do need to understand the internals. And that's why our course async techniques and examples and Python show you how to write async code successfully as well as how it works. Get started with async and await today with our course at talk python.fm slash async. Sebastian, welcome to talk by enemy. Thank you very much. Thank you for the invitation. It's a great pleasure to be here. Well, thanks for building a cool Web API.

01:45 You're welcome, I guess. Yeah, it's gonna be fun to talk about it. Actually, I think, you know, it's been really interesting. There were a lot of web frameworks that came out and 2005 2008 timeframe, then I feel like it kind of stabilized for a long time. And then I'm not sure exactly what it was. But I think that the async and await stuff coming along, sort of pushed the creation of a bunch of new frameworks. And all of a sudden, there were there was another framework every other week. Crazy. And yours was kind of in that second wave or whatever wave that was. And yeah, it looks like it's getting a lot of traction. So that's awesome. Yeah, thank you very much. Yeah, I actually feel pretty much the same. I feel like they will like a couple of waves of frameworks, and then a second one, and I was actually avoiding building a framework for a long time. Yeah. Yeah, I can imagine. I definitely wanna ask you about that. But let's start with your story. How did you get into programming in Python? So I'm not sure if I go to do some Python when I was little. But when I really got into it was in I think, when I was 20, something I was doing a bunch of courses online. And one of them was I was doing a bunch of courses actually doing everything in JavaScript on the browser, because no GS was just starting to be something. And one of them required Python for doing artificial intelligence and stuff. And I ended up like, yeah, let's just try. Let's see if I can do it. And I ended up just like, learning the basics of Python for the course. And it was super intense, but I ended up loving it. And yeah, I just went on with Python for everything. Oh, that's great. You know, Python is one of those things that learning Python is really interesting, because it's both super approachable, but kind of never ending like, I think one of the guests I had on not too long ago, told a joke, or talked about a T shirt. That was kind of a joke that said, I learned Python, it was a great afternoon or something like that. Yeah, which in one hand, like you can learn the syntax, and you can make things happen, or follow along a simple example. But you know, I'm still learning Python all the time, right? Like learning about your framework, I learned a bunch of stuff that I needed to figure out, because it depends what you call Python. Do you call Python? Is that the language? Or when you learn Python? Are you also talking about learning the standard library? Or if you really want to blow it up, then like, the stuff on pi pi, right? Like, you know, there's these different levels. And you hear people say, Oh, I learned Python really quick, or I've been learning Python for a long time. And I'm still working on it. Those people are probably not talking about the same thing, right? Yeah, absolutely. And then you get into numerical computation and processing stuff on GPUs. And it's like, a whole different story additional to everything is, yeah, so yeah. Oh, for sure. For sure. Yeah. And I only bring that up, because I know there's a lot of people who are like learning Python and getting started. And they're probably a lot of times they're like, I'm still working on it after a year. You know what I mean? And I just, it's really interesting that people say the same thing. And there's like these layers that they're talking about. Cool. So you got into programming, or Python dragged into the data science side of the world. That's cool. And what are you up to these days? So right now I'm working for explosion in Berlin, Germany. explosion of the Creator

05:00 dose of spacey the natural language processing package for doing things like machine learning over a text, the Prodigy the package for doing data annotation using active learning. So to annotate machine learning datasets, and think the Deep Learning Library for doing well, deep learning using IDs from functional programming, type annotations, and all these things in a way that is compatible with all their tools like pi torch TensorFlow, etc. This is the company I'm working for. I'm working on the team that is building brother g teams. So the version of prodigy for teams to have like multiple people in the same company, interacting with each other coordinated. And doing all that is like the cloud version. But the important thing is that it runs on the clients cloud on the specific company's cloud. So data is like stored on all the privacy stuff can can be like safe and all the stuff. Yeah. So that's what I'm doing like, mainly in explosion, from time to time, I also help with some mixture of things from the other projects. And as part like, I have the privilege that part of my work is maintaining my open source tools and projects because we use them internally. And because explosion is very cool. Yes. Yeah. Yeah. Like I get to spend like, a fifth of all my working time Joza allocated to this open source tool. So yeah, that's mainly my day to day. Well, I that sounds really fun. And yeah, explosion AI seems like a cool company. Now. We just had Enos on Python bytes on episode 191. So a little while ago when the ships but you know, in calendar time not long ago. Yeah. I'm guessing that you are probably using a lot of working a lot of the API side of that product. Right. Exactly. Yeah. Yeah. Mainly on that side. Cool. Well, speaking of API's, let's start there. Obviously, it's all about consuming API's. These days API's are everywhere. You go to Zapier, and they're like, we integrate with, you know, however many thousand different API endpoints that you might want to work with. And it's Yeah, it's all pretty crazy. But of course, creating API's is super important. So focusing on that side, how have you seen the evolution of API frameworks coming up? Because the early days that I spoke of, it was like things were web frameworks. And then if you wanted, you could somehow manage to put a web API in it. Yeah, absolutely. Exactly. I think that's the key difference. I think that's exactly the key difference. Yeah. Because Yeah. So for example, this framework is basically, I don't know what you would think it was something like API first. I mean, obviously, it's in the name. But there's a bunch of them like that these days that are coming outwards, the building blocks talk in terms of API's, not in terms of web templates, and whatnot. Yeah, exactly. So like, I guess, for a very long time, the more established frameworks in Python specifically have been flask and Django. And for API's, it will be in Django will be Django rest framework. In flask, there are a bunch of plugins that can be combined together to make something that works very well. The same as with Django rest framework does. The thing is that as you were saying, these frameworks were made, mainly to handle templates in the back end. So they extra plugins, and the extra functionality was added on top around the ways that the framework was able to do things. So and as you were saying, like, there was this bunch of extra frameworks that came afterwards, like several, even at the same time, sort of, and they know the async wave came with a bunch of other frameworks. Past API ended up later in that last wave, I guess. But it was mainly from the learnings of all these previous frameworks. I was using a bunch of those frameworks for a long time, a bunch of plugins, a bunch of combinations, trying one thing, trying the other, I had like something that was kind of stable, but still very difficult to maintain, and quite fragile. Yeah, you said that you didn't really want to build fast API. But finally you decided All right, yeah, I need the thing I want to exist. So here we go. Yeah, I felt like the meme of, Hey, I built another JavaScript framework is having like every week or so. And I was trying really hard to avoid that. And I was trying, like, No, I just find the thing that I'm looking for and find the thing that will do the functionality that I need. Yeah. And at some point, when I was like, yeah, I'm not finding the right thing. I found it. And it was API star was the name right. API star was a framework built by Don crease, the great guy, the same creator of Django rest framework. Yeah, exactly a successor Django rest framework, but from scratch. Exactly, exactly. And that was APA star and APA star was trying to be compatible with whiskey and ASCII. So like the canonical standard specification, or interface for web frameworks, which is what flask and Django are based on.

10:00 And at the same time with ASCII, which was the new standard that was also born at Django for doing WebSockets. And all these synchronous things, right, it's probably maybe worth just pointing out to the people listening who are not deep in the web hosting side, like whiskey is this common API that all the different web frameworks, flask, Django, and so on, come talk to, or implement. And then all the web servers like microwaves, gi G, unicorn, and so on, know how to talk to anything that does whiskey. And that's how you can run all the different frameworks on these various web servers. But none of those were capable of supporting async programming, which is super important for scalability on the server side, because just the way that thing was written is incompatible with that. And so there's a another standard, I think, yeah, maybe Tom was even partially involved in like defining the standard, not sure. But a SGI for async. gateway interface, and that's the SGI that you're talking about. Right? So API star is trying to do both of those things. Yeah, exactly. And complementing over you were saying, like, these specifications of how to interact with the server on the on the framework are actually like, quite simple. It's mainly kind of one page. And it just says, like, there has to be a function that is going to be called with these parameters, and is basically that, but then they're finding what is the shape of that function? What are the parameters that is going to receive all that is like the main point of interaction between a server like unicorn and a framework like flask. So these new these new these new standard as gi is the one that adds support for async and await and all these things. And it started was trying to have support for both things, while being an API first framework. And having like a bunch of extra features that don't press the add it and it was great. I was just trying to add some authentication ideas to be able to integrate them with API first things. And at that point, don't Chris It was also building starlett, which is the microframework is a toolkit for building API's in as in these new building API's not sorry for building like web applications or for doing web stuff, using this new standard. So it's like the bare bones thing is kind of in the middle of flask and a lower level tool, it will do like kind of the same things. And because he was focusing on that he had to deprecate most of the API star components, like the server components, and made it just like a system and a set of tools to validate schemas for API's. Right. And at that point, I just had found the perfect tool, and then it had to be deprecated. So I guess that was the cue that was like, Okay, let's try this. And at the same, you know, that is a little bit unfortunate. But at the same time, you now have starlet, so you don't have to write that layer, you can work a little bit higher level. So Well, let me just put my take on an API for building API's met API. They're on top of starlett. Right. And it's likely Yeah. So is that it is like one of the fastest or I guess the fastest framework for Python, currently, like as measured by independent benchmarks, right? Checking power is one of these people. Yeah, exactly. They, they measure, not just you're not seeing that for Python frameworks, right? That's like a general statement, for many of the way they test all the different web frameworks, Python, Ruby, dotnet, Java, and so on. Yeah, exactly. and a bunch of other languages and with a bunch of combinations of databases and stuff. So they have a great job. And they do like testing rounds on physical servers. So it's like a very, very robust and well made general benchmark. So it's quite nice, because lets you like see more clearly, what are the things and the advantages and disadvantages? Of course, benchmarks are always somehow biased in one way or another and difficult to handle and to interpret that, at least like it's a very, like a very common ground. I think these ones right. So then started it was this new tool, and it was built by Tom Kristensen, creator of Django rest framework, the creator of the thing that I thought was the perfect match that I was looking for. So it was like a very, very solid option to build something on top. Yeah, I remember API's are being really nice. I was sad to see that it got semi deprecated as well. Yeah, yeah. I know. But I mean, if we have fast API, because I think that fast API is actually better. So it sounds to me like you're pretty happy with your job at explosion. AI. But you did have this, you did run across this interesting job ad assay. And you sent out a tweet. And oh, my goodness, did that tweet take off. So it said that it was looking for somebody to work in fast API, and it's suggested that they have at least four years of experience with it, right? Tell us about this. Yeah, exactly.

14:59 Exactly.

15:00 Because I thought like her, this is kind of a funny story. And actually I have seen several job posts requiring similar things like for us APA specifically requires several years of fast API and for CPA has one year and a half of existence. And I saw the job post and I was like, it's kind of fun, but not fun enough. But one day, I was like, yeah, let's just do it. It is not really that fun, but whatever. So and then it was a, I saw a job post from a four plus years of experience with a CPA. And I couldn't apply because I only have 1.5 years since I created that thing. I'm like, Yeah, well, like, maybe it's time to reevaluate that years of experience is equal to the skill level. It was actually I wrote it, and I was like,

15:46 it's not that fun. And I asked my wife and she said, like, yeah, whatever just posted. Yeah, exactly. Someone might find it fun. And, and then like, two hours later, it was like 2000 likes or something like that. And it started growing like crazy. You probably almost had to like turn off notifications on your phone at that point. If it's just ding ding, ding, ding, retweet, retweet, like retweet. Yeah, exactly. Like, I tried to open the Twitter app in my phone. And for two days, it was just crushing immediately, it wouldn't even open and I didn't even know like, how is this thing? This is so weird. And if you see my Twitter account, you can see like, the tweets before that or after that, right. 30 likes 50 legs? like yeah, you really struck a nerve. Yeah. You really found like this idea of like, Oh, yeah, I guess we all hate this idea. And it's all the time, right? Pretty funny. Yeah.

16:44 This portion of talk Python to me is brought to you by linode. Whether you're working on a personal project or managing your enterprises infrastructure, linode has the pricing support and scale that you need to take your project to the next level, with 11 data centers worldwide, including their newest data center in Sydney, Australia, enterprise grade hardware, s3 compatible storage, and the next generation network linode delivers the performance that you expect at a price that you don't get started on the node today with a $20 credit and you get access to native SSD storage, a 40 gigabit network industry leading processors, their revamped Cloud Manager cloud not linode.com root access to your server along with their newest API and a Python COI just visit talk python.fm slash linode when creating a new linode account, and you'll automatically get $20 credit for your next project. Oh, and one last thing they're hiring go to lynda.com slash careers to find out more, let them know that we sent you

17:44 did about a year and a half ago, let's talk about some of the core features because I really, really liked the way that you put this together. It brings together two or three my really favorite things about some of the language stuff, it type annotations, it makes those like first class citizens in a right way to put it a non artificial way. Because I've seen people on other frameworks use type annotations, but the types are meant to talk to the framework, but they're not actually the types you end up with, you know, like things SQL alchemy, like you would say that. Yeah, default, the type is a column type. But really what you mean is it's an integer. So I mean, that's not SQL alchemy doesn't do that. But there's some web frameworks that kind of have that similar take. So type annotations, the async and await stuff on the server. And then also this, this ability to have like a model that defines what you expect to be coming in, and the ability to not have to do that juggling yourself. Yeah, exactly. I think you're right, if it is better than, well, yeah, that was the idea I wanted, like coming from what I had seen on APA star, and with the idea that you could maybe add some extra information about the parameters of going to a function in the same declaration of those parameters, then I wanted to extend that a bit. And that's when I found bidentate, which is a library for doing data metric manipulation, which is awesome, independently of if you use pass API or not, it's great by itself. And the way it works is that is pretty much the same as with data classes buried at the additional data validation and data serialization. So if you type something that is declared with a type of an integer, and you try to parse something that is not an integer, it will try to transform that into an integer and try to serialize that and convert that to the actual integer that you're declaring to receive. So for example, if you say that parameter in in a URL should be an integer that say the user ID identic can take that and transform it into the an actual integer so that the code internally receives an actuality. Right? So ficpi uses all these ideas from pedantic and the internal tools to integrate that with the framework itself based on top of Sterling, and as you say, I will

20:00 Trying to hit exactly that point of being able to use the type annotations in the standard way to use the standard type annotations, for example, to use, if I wanted to have a string to declare it as a string, not having to import some specific, strange class that was declared by fast API or something, but just using the standard string as a type annotation, and they get all the type support in the editor, like auto completion and type checks and all these things, having them by default, working gussied up with any code base that is type annotated. So like all those features, and on top of that having the data validation, so that data is valid at the point that your code starts to run, you don't have to do all the validation by hand, and data serialization. So for example, like with pedantic, you can create, say, a user class and say it has an ID, colon int, and a name, which has a default value. And then another thing, like a date time, which has an optional of say, daytime, and so on. And if I'm reading it, right, the ID that doesn't have any default value, but it's also not an optional idea is a required field, probably the name that has a default value exactly, is optional, and would take that default value. And the option one that is explicit, also would have an optional and so on. So like, if there's a concrete type, it's both required and converted to that if there's a default value, if it is that type, but it's also it's not required, and so on. So there's a lot of nice nuance with almost nothing but like this field, is this type and either is optional or not, right? Yeah, exactly. And the idea is to like, use the same the same way that standard Python works. So like the same way that you declared that a function parameter is required, it should still be required, which is like by not declaring a default value, then it is required. So it's interpreted that way. So the idea is that it just like cooks the standard intuition, and uses that to provide all the extra features. So it should be just like very intuitive to work with and just work well by default, that that's kind of the, it's beautiful. And then also, because of the way that it's put together, it leverages all the stuff that tells the editors what to do. So if you get your value, and you say you know.it knows what type that is and what to autocomplete, right there. Exactly. And because you can also have like very deeply nested and complex data structures, like you can say that your API is going to receive a list of orders of food. And each one of these food items is going to have a name, but can also have a list of ingredients, which each of them is going to be a string. So it's like a very nested and complex to even to explain a complex data structure. But then be able to have auto completion even for the ugliness that little beats inside of the editor and paychecks and all that. Like for me, that is the like, Wow, this is so cool. It's so cool. And like is if I don't think that is Yeah, you know why it's so cool is because that's the part of programming that just sucks. Like he just it's not fun to go just go like okay, does it have this? Does it have this? Is it this the type? I tried to convert it? No, it crashed. Okay, those are the nuts is like, there's not much value in that. But you have to be very careful and specific. And just, if that could just go away like this, and something else handles it. It's beautiful.

23:22 Yeah. And also, I think it's like, at least in my experience, it has been one of those pieces of code and logic, that is, in many cases neglected, at least in the beginning. Like when you say, Okay, let's build an API, then you just add flask, and yeah, it works. But then you're not taking into account all the corner cases and all the invalid data problems and all those things. And it's very easy to miss that. And to not realize that you have to validate all that stuff. So having something that kind of enforces you to do it. And those by default, that's like is like the main benefit, right. And so when that fails, validation, what happens to the client get a 400 bad request with some kind of message about how it failed? Yeah, exactly. So when you declare so let's say you create a class, a user class that inherits from this thing from by downtick and you say like, I'm going to receive a food that that has a name and has some ingredients, and you declare the parameter inside of the function with using the standard type annotations, you send the food colon, this is an instance of this class food. So you have like standard Python type annotations, and your code will be executed, like the code inside of the function that will handle that request is going to be executed only after the data is validated. That's fantastic. So if someone says,

24:45 Yeah, I think that's pretty cool. because it saves like, I don't know, 2050 lines of code inside of each one of those functions that is just on automatically. So when data is invalid, and it gets to the server, data is going to be validated, and all the

25:00 So they're going to be like check and the clients is going to receive is for 22 error. Yeah, is 400 range error for 22 is the process of all entity. And he's going to tell the client exactly where is the error is. So it's not only saying there's a invalidate in your request is saying exactly inside of this point, deep in your deeply nested data structure, like one of those ingredients in the food items that you sent in your orders. One of those ingredients is not really a strange. So exactly, there is a problem. Wow, yeah, that's awesome. I love it. And you set it but I'm not sure if it totally sunk in. All you have to do to make this happen is you create an API endpoint. And then you say, it takes a class an instance of a class. So like, it takes a food, colon food. And that's it. You don't have to like get from some dictionary and like copy it over or like fast API will look at that and say, Oh, it's the thing that I have to supply this function or call it is this. So I'm going to take the posted JSON data, I'm going to run it through pedantic, make sure everything works. And in that case, I'm going to deliver to them to start off a fully validated one of these things, pre populated strings converted to integers as they need to be and all that right. Yeah, exactly, exactly. As you say. It's just like declaring models is like declaring the models of database in with an ORM. And then you just receive the thing that you declared. Yeah, exactly. And if the client didn't send that, then you just won't receive it. And the client will receive an error automatically. So it's just works. Yeah, by default. That's super cool. I guess the other point around one of these core features here that we're talking about, this isn't the thing necessarily that like, made me go Yes, is awesome. But it's nice is that it's API first. So if I was in, say, flask, I would say at app dot route, give it the URL. And then optionally, I could decide to filter down the HTTP verbs I could accept, I could say, is it methods equals get comma, head or something like that? Right? Those could be the things Yeah, but with your API, it's app dot get URL, or app dot post. And so you speak in terms of I want to handle this verb, and this URL here, which is a very API way of thinking about the world. Yeah, exactly. And the idea with that was the in many cases, it's very easy to end up having a bunch of logic to handle, GET and POST in the same function. And then all that logic is actually like, very cumbersome to untangle because it's handling different ideas and different cases, it might share some code, but it's mostly different ideas. In most of the cases, yeah. And I've seen it too. And it's such a bad idea. It's like, why would you say if method equals get, here's part of my method, else, if it's post do this, that just make that two methods and just set the method, the verb to be the two things in which case, like what you've got here, it just leads you more naturally down that path of this is the one that does the get, this is the one that does the post. And it kind of, there's this cool concept of designing API's or ways of consuming stuff that I like called, like, helping users fall into the pit of success. Like, if you don't know what you're doing, you kind of fumbling your way around, you're gonna land into the place, you should land. You got to find a place to like, do it wrong. You know what I mean? I hope I really hope so. And this helps people fall into the pit of success. And it's also that I waddled around the into the,

28:35 into the neighboring places, that didn't work very well. Yeah. And then like glaring from these things, learning from all these best practices from different API's from different tool from different plugins is like all that learning is what I tried to put together with first appear. Yeah, well, well done. I think. So. Because all these things we talked about are the stuff that you've put together. But because in terms of defining the API, but because it's based on top of starlet starlett, itself has a bunch of cool features as well, right? Yeah, exactly. It started this low to start fast API is actually kind of a theme sort of thin layer on top of Istalif, adding the pythonic parts, and combining it all together based on the standards based on the open API JSON schema, or to all these standards from the web that you just like get by default. When you see when creating a first API application. That starlet is the thing that is actually doing all day. Web handling is the thing that it provides all the performance and style it has support for so fast API also has support for WebSockets. Their cc a graph qL integration, you can have templates the same as you will with flask or with many other frameworks. So you can actually build a web application based on templates in the like, same way as you will do with the older established

30:00 remorse is just a does not weigh change. But yeah, like you can have all these different things by default, just because it's based on started. So if I wanted to rewrite my website, most of which is in pyramid, some of which is in flask, I could do it with fast API. Yeah, actually, I imagine you will have like a bunch of Jinja, two templates or something like that, then you can just preserve the same templates, and you just reuse them and pass them to fast API, which is not, there's not that huge benefit from that. Because like, the logic will end up being very similar. And ficpi won't provide a lot on top of what other frameworks made with templates will do. But yeah, you can actually do it fairly easily. Yeah. Okay. Yeah. I mean, we do have a bunch of API's for like our mobile apps and stuff. And it'd be nice to write those differently. Yeah, absolutely. Yeah. Cool. So there's a bunch of features you get from starlett. And because this is the layer on, on top of that, you basically get all the features of starlet plus, we mentioned a SGI couple times. Yeah. And so I'm guessing I can do an async def view method or API endpoint. Yeah. So when things started is based on this standard ASCII so you actually can get like all the things that are compatible with ASCII. And there's a bunch of tools and additional like middleware and things that you can integrate directly, because he's based on one of these common standards. Like it's an open standard that everyone can implement. So you can add, I don't know, century, you can add the data dog, you can add Elastic Search like that the logging functionality, you can add, like a bunch of things right there that are not necessarily even made for faster API or for started, just because they adopt the same standard, you can get like all that as well. Okay. Super cool. And you support async methods? Well, yeah, of course. So fast API is actually like, mainly well actually started it is mainly an async framework. So you will use async def, for your functions, if you want to have like all the performance, and you know how to use async and await async. And await are like provide a bunch of performance and performance in concurrency scenarios, which have performance benefits, but they have like their own ideas that you need to be aware of, to be able to use them properly. So you need to be able to use tools that are compatible with async and await. So if you're using async await, then you can take all the benefit from that. But with the solid and fast API, you can also use standard function definitions, and then it will do like the smart thing. And we'll run those standard function definitions underneath in a thread pool. So it won't the technical details is that it won't block the event loop. But the thing is that it won't degrade performance, or they won't do something that actually ends up like a hard thing, the whole application. So if you are not sure or if you are doing, I don't know machine learning stuff, then you can just look use a standard function definition with just def, whatever. But when you want to, or when you need to have some of these async ideas. For example, when you need to handle WebSockets, then you can use async functions. Oh, that's really nice. So you don't have to adopt the async API's in order to work with it. But you can if you want to. Yeah, exactly. And for example, you can, if you have a bunch of SQL alchemy models with a flask application or something else, then you can just reuse exactly the same SQL alchemy models and reuse the event, the same database database, so you can actually have both applications running at the same time and then just use the standard code as you will with normal def functions. Very nice. I think most people probably don't need that, right. Like most of the time API's are fast enough, and they're just fine and, and whatnot. But when you do need them, it's really awesome that that capability is there to say, the answer is not I have to go rewrite this and no JS are and go it is I just need to use a different thing HTTP client that I'm consuming my API with, like HTTP x, or something that supports async grindy, to use slightly different ORM library that supports async. And await write like a small adjustment rather than a throw it all away and start over. Exactly, exactly. And in fact, you can combine those in the same application. So you can have like a bunch of standard function definitions for most of the application, and then you need one that needs to have like, all the maximum possible performance you can have like I don't know, maybe leader our SQL statements connected to a sink a Postgres driver or something, and then do that only for that specific endpoint that needs to have like all the maximum performance and then the rest, you can just do the Standard Code, right. And in fact API, there's dependency injection system that can be used to handle database Asians and a bunch of things but also to do things like syndication.

35:00 authorization, getting, for example, getting the current user from a request, things like that. And it's all all gets integrated into the automatic user interface that is generated. But the cool thing is that you can actually combine async and normal function definitions for these dependencies that can depend on one another. So you can have different async and normal function definitions even for the same route that you're handling even for the same endpoint. Oh, wow. Okay, that's pretty awesome.

35:31 Talk Python to me is partially supported by our training courses. How does your team keep their Python skills sharp? How do you make sure new hires Get Started fast and learn the pythonic? way? If the answer is a series of boring videos that don't inspire, or a subscription service you pay way too much for and use way too little. Listen up. A Talk Python Training, we have enterprise tiers for all of our courses, get just the one course you need for your team with full reporting and monitoring, or ditch that unused subscription for our course bundles, which include all the courses and you pay about the same price as a subscription. Once For details, visit training, talk python.fm slash business or just email sales at talk python.fm.

36:15 One thing I think would be fun to do is maybe compare this to flask at an API level. And there's a cool article, I don't know, have you seen it this article called fast API for flask users? Yeah, it got a lot of attention. And it was actually very important with the most of the things like how they are different. Yeah, and the advantages and stuff. Yeah. So this is article by a meet Chen Tari. I'll link to it. But basically, he goes through and says, alright, you know, flask, here's what you would do if you were to convert your app or rewrite it or just learn fast API. And I think a lot of people out there know the API for flask. So I think it'll be a quick comparison. So the first one that we talked about a little bit is that this is a API first, not a page first or URL destination first. So instead of app dot route, you have app dot, get app dot post, and so on, and pass the URL, of course, that's that we talked about, I think one that touches on some of the stuff, some of the advantages are, you've got app dot route. And then you can specify a variable in there. And in flask, it's nice as well, that you can say this variable is an integer, or it is float or something, and it will look at that. And it'll require it to be an integer, and it will cast it to an integer and then pass it to you. Right? Yeah. But in your framework, you just say there's a variable in the function, you say it's an integer, which I think is better. I mean, it's sort of equivalent, but it's better because the tooling, my PI, PI charm vs. Code, they all know that it's an integer, whereas the flask version, it just happens to be. Yeah, so the thing is that flask was made in the Python two point something versions. So it did like it's such a great syntax and some great ideas that used the available options that were there at the time. But then the thing is that you end up having to learn this extra syntax of where to put like, what is the type of what is the variable? And what is the symbol that you have to put on the side, like, there's like a little extra syntax that is specific to flask that you have to learn? The idea here was to use the same concepts are like now part of Python itself. So for example, to declare a variable you don't use, how do you call them like Angular braces? Or like less than one more than you use the angle brackets? Yeah, yeah, you use curly braces, which is the same one that you use for f-strings. So it should be relatively familiar. Yeah. And then to declare that tight is just like in the function, which you will probably want to declare to type in the function either way, even if you were using flask instead of a set. Yeah, just to get like all the type support from the editor and from tools. So exactly, that's what I do I but you've got to have it in two places, right? You got to have it in the route definition and in the function parameter, and they could get out of sync, which is annoying. I mean, this is not a huge, a bash on flask type of thing. Like you said, it just predated the concept of type annotations. Yeah. And actually, like a lot of the things in first API were learned from flask. And from a bunch of additional plugins that were compatible with flask, including marshmallow and web Rx, and flask API spec, that were great tools. And those were my favorite tools like apathy, like built fast API to be able to have like that functionality that they provided, but like taking the advantage of the new type annotations. But yeah, it's like fast API wouldn't exist, if it was not for the learning is provided by all these previous tools. Yeah, for sure. Another one query strings. It may be more general, right? Like, if I understand it, right, fast API will take the data from all the places that is provided to your endpoint, right. So obviously, if you post a JSON document or a form, it'll take it from there and put it into your UI.

40:00 But also from the query string from the headers from the cookies and so on. Right? Yeah. So basically the way that you declare that you, let's say, in many traditional frameworks, you receive a request a request object, or you import in some way, you have some type of request object. And from the request object, you extract data, you get JSON data, you get query parameters, you get path parameters, cookies, whatever. But you start with a request, that is the same for all your functions in first API, you can actually get the request and get the data by yourself directly if you want to do so. So it's actually also available. But the main point of direction now, the main point of extracting the data is not getting a request object, but declaring the parameters in the function and those parameters will be extracted, validated, and everything from the request and also documented, because when you create an application with fast API, you get automatic API documentation in a web user interface that you can explore and use interactive. So like the name point of information extraction is in those parameters in the function. Yeah. And what happens if it's missing, right? Like a query string is something that may or may not be there? Yeah, for example, let's say that you have a string that you call like, yellow Q, because it's, you're doing some maze query search or something, if you declare it, right, right. So you have like, endpoint question mark, q equals some value on a search for? Yeah, exactly, exactly. Then you declare the function, and you add a parameter that is called Q, because the parameter is called Q, they pass API will look for a parameter in the query that is also called Q, then you declare a type for that parameter. That's a string because we want text strings. So fast API will make sure that it's a string. Well, given it's a URL, it will always be a string, but you could say like, it's a Boolean, and fast API will make sure that it's a Boolean, right. But then you can also say, hey, this thing is optional. So by default, these will be none. So that means fast API, like in the Python world with like, independent of us API, when you declare a function that has a default value, then that parameter automatically is not required, the first API will use that same logic and made the parameter not required because it has a default value. You could use that, for example, to say, like I want to get I don't know the users. And I want to limit the amount of users that I want to receive by 200. And I want to skip the first thing or something like that, you go have default values for those query parameters and say, like the default value is to skip zero, because you want to get all the users from the first one, and the limit is by default, 10. Right, then you will get those values in your code that the user provides them in the query parameters, then fast API will read that from those query parameters. So you actually use the same ideas that you use in normal functions to occur when something is required or not. Like this is the basic case, there's an additional case where you want to do additional data validation on those specific query parameters on those specific data that you're receiving, for example, you want to make sure that the query is not longer than right 100 characters or something like that, you can do additional validation for that with another technique, but in the basic case, is just like the same way you use for standard functions. Right? Like, if you wanted more validation, you could have a search parameters identic type could have a field Q, and then you could put the pedantic requirements and restrictions there, right? Yeah. And actually, like, first API will, if you declare a parameter that has a simple type, like a string or a Boolean, or something that doesn't, they will try to read it from the query. But if you want to read it from let's say, from a cookie, then you can import another utility from fast API and make the default value of that parameter, the that thing that you important, which is a function, and you just call it and that tells us okay, hey, I want this thing to be retrieved from the cookie, not from the query, that will be the default. Right? Right. That's a really interesting angle as well. So because of my stuff is in pyramid, a lot of it predates or is, like, right on the verge of predating the type annotations as well, certainly the framework is it gets this request and like, you've got to go, Yeah, what's really annoying about when you're given the request is it's not just like, here's the data. It's like, No, no, there's a JSON body thing, you got to go check. There's a, there's a form, you got to check the query string, you got to check. There's the headers there. There's all these different dictionaries, you got to go check. Right? So what I've done so far is I've just, I've set up some sort of lower level infrastructure that like, will just take that and merge it all into one giant dictionary and go, here's the data you've been provided, you can ask for it, you know, the Forum has or the URL as higher priority than the forum which has higher priority than like, you know, query string and all those kinds of things, right? Yeah. But yeah, this is nicer.

45:01 I'm glad you like it. Yeah, for sure. But yeah, it's actually it's one of those things that everyone ends up having a taste. And sometimes people come like, Hey, why are you doing it this way and not the other way that I prefer? And it's like, well, yeah, like, I had to make some decisions and have some defaults. But you can actually customize it to have whatever you actually want. One of the things, I think the API is a lot like flask. And I think flask is a very popular framework. But what's even more popular is the basic API of flask like, you look at Sanic. And it's kind of flask like you look at responder, it's kind of flask like, you know what I mean? Like, yeah, this idea of I create an app, and then I do app dot route or something to the equivalent. It's just super popular, right? One of the drawbacks of that API, and maybe the cute little demos of like, Look, you can in like 10 lines of code, right, your web server, and it's all great. It can send people a little bit down the wrong path of like, well, now I've got this app object, and I need to use it as the decorator on my stuff. So I guess every single one of my API or view methods just goes into like, the main app.py file, right? And, you know, I think a lot of the tutorials and stuff lead people down the wrong way by just saying, well, this is just you just use App, right? You just use that and, and in a real app, you would be hurting. If you put that I mean, there's hundreds of API in for web endpoints and my apps. And you want to put those into different modules, right? Like, oh, here's where I deal with like, say your food example. Here's how I deal with the recipes. Here's how I go and get like a particular thing for the food. Here's how I get like my preferences, like those are not all the same place, right? Yeah. So flask has blueprints, what does fast API have for the ability to factor your code into what I would call real applications. So fast CGI has this additional tool, very similar to blueprints, actually viewed search for blueprint, flask blueprints. In fact, again, you get immediately to the docks, on how to do that. There's this additional class comparable to the fast API class that you use to create an app that is called API router. So you can create independent routers that are all in their specific modules, which work pretty much the same as the main app object that you will use to then you just have like, I don't know, router dot get and the URL that you want. And then you can import all those routers in your main application and include them in the main application. And you can actually include them adding a prefix for the path. So you can have like, let's say, one module, one Python file for users, and then you have Joe's router to get his lash without even having to apply slash users slash GGC relative dot get slash, and then it will provide you all the users but then at the time that you include that, in the main application, you say, everything that comes from this module should go with the prefix is slash user slash. Yeah, that's fantastic. Because that's usually the thing that tells you how you want to break up your endpoints and group them, right? Like, here's all the stuff that slash admin, here's all the stuff that is slash users and so on, and you just enforce it right that way as well. That's great. Yeah, exactly, exactly. So it's actually quite simple to do. And you can like structure the application in a very simple way. It's actually part of the main documentation. documentation is is structured in a way that is a user guide. And at the same thing kind of reference, but it's made in a way that you can go one point up there to go there and get like a full system with all the basic stuff. And there's another section with all the extra advanced stuff. But then you can get like learning all the bits and pieces and get to one of these things where you have an application built in with separate modules that are work together. Yeah. Cool. Another thing that is common around API's is not very common about around websites, but is quite common around API's is you need to document what are the endpoints? What are the expected values, like your JSON documents look like this. This is required. It's an integer. This is optional. It's a date, time and so on. What's the story for that here? So the I guess I suffer from that maintaining a corporate Wikis that always got up so late, and the front end team came fighting like, hey, this thing doesn't work like no, it was a beta that we can go. So when you create an application with fast API, it's all faster API itself is all built around open standards. So when you create an application with fast API, you get an API that is based on standards, and you get an open API schema. So the standard is called Open API. And you get a schema, which is just a very big JSON that the current describes everything in your API, all the paths or the parameters, everything. This is a big JSON that you actually kind of never look at, because these JSON is read by a user interface that you can see through the web.

50:00 browser that documents all your API and that you can explore and actually interact with it life. So you can you get automatic interactive documentation in your web browser included by default, when you create an application and you can use, it's fun because sometimes people ask me, like, who is the user of that user interface? And like, when you start this, like, you assume like, no one is going to use it. And maybe no, maybe it's just like for the final client or, but then you end up the final client ends up using it, the front end team that you have to communicate, and then you yourself end up using it to see like, Hey, is this thing working or no? So you don't really end up using it a lot? Exactly. Or what does the system think? I told it, I want, right, does it? Does it think this is optional? Or not? optional? I want it to be optional.

50:48 Yeah, exactly. Exactly. The thing is that because you don't have to maintain any documentation outside or you don't have to include like additional configurations or schema inside of the, I don't know, the doc strings or things like that. It's all generated automatically. You don't have to do any effort to get that like, just by writing your standard code, you get that kind of for free. So that's really helpful when developing and when using Yeah, for sure. If I were to put a doc string that just was like a summary of what happens, would that show up in the documentation? Yeah, exactly. That those string will end up in the documentation in the interactive documentation. And you can actually use markdown and it will be rendered us a markdown. Ah, sweet. So yeah, it works as it should. Awesome. Yeah. That works pretty well. And you also have like the utilities to document each of the things that you declare, like, if you look at one of these classes that we were mentioning, you can have documentation for that specific class, which will be like a JSON payload, that it will have its own description, like, each one of the fields will have its own description that you can say, name, this refers to the name of the food that you are requesting, or whatever. And it will be all there in the code, and it gets all rendered in the documentation. That's super cool. So two final things I want to talk about one, I was going through the documentation, and I saw that there was some optional dependencies, which is pretty interesting. Yeah. And so for example, it says, some are used by pedantic Some are used by starlett. Some are used more directly. But for example, I could optionally use micro JSON uj, s o n, but the mew write the Greek micro, which is a faster implementation of JSON parsing. And I guess if I just do pip install fast API, it just installs what it requires. But maybe it uses just the built in JSON parser, right? Yeah, exactly. By default, it will use the default JSON parser, which is like more standard and handles like all the cases in a more standard, quote, unquote, way. But if you need to have like the maximum performance, you can also install the JSON and the tail fast API, hey, I want you to use not the standard JSON responses, I want you to use the JSON responses that use these huge JSON library to serialize all the data. And actually, very delimitation, I think in the main point where I say like, these are the optional dependencies, there's something that you JSON is the only one mentioned. But you can also use our JSON, which is equivalent to you, Jason, that is written in rust, and in some benchmarks is faster than your JSON choose, you actually get like different ways to optimize wherever you want to do and to optimize, like independently for each one of the things. I need one of the endpoints that you need to have. Interesting. Yeah, and you also starlet has an optional aIIow files dependency, which will give you async and await capabilities for working with files and that plugs into like file response and static file responses and stuff like that. Yeah, exactly. So it's actually the starlet is really, really lean, like the main code is very small. And it's actually beautiful. It's a really enjoyable to read. And it just plugs into different components and different parts for different things. So we use is sterile it alone or FASTA, gay alone, for example, it won't include any ORM. It won't include Jinja, by default, because you don't necessarily have to use templates. But if you need them place, then you just import ginger and use the templates functionality internally. So it's made in a way that doesn't require all the possible dependencies, but you can install them and then just use them internally. That also allows you to have like very minimal applications that are not bloated with different packages and dependencies and things right but at the same time, you can grow very large to solve the use cases that you that you need to deal with. Yeah, that's cool. It's like microframework philosophy adopted there. Yeah, exactly. Exactly. Last one is about hosting. So I saw that it ships with you via corn, which

55:00 is like the hsgi Python server equivalent of G unicorn. But based on UV loop, is that right? Exactly? That's exactly correct. So you've got UV loop is a high performance async and await like event loop, basically written in C or something like that. Yeah, and you can loop is the thing that has been providing all these high performance for all these high performance frameworks, like starting with Sonic, the main idea they had was, let's run everything using this additional optional, a loop that is going to do all the synchronous stuff. And that's what provides all the huge performance. So starlet and fast API are frameworks, which is one of the sides of like the whole process, like when we were talking about this specification, this as gi or as a specification. On one side, you have the framework and on the other side, you have the server, you'll be gone will stand on the server side, you can use unicorn, but you can also use another one called hypercard. Or you can use the one that is created by the same guys from Django, which is called Daphne. And you can use for example, you can have unicorn, which like starts a process using this Yuval loop server. But you can also have Guney con, the standard you will use for flask running a worker of unicorn like and running several workers. So you can have several processes that all have like these massive high concurrency, serving your application, all handled by the same unicorn as you will normally do, which is probably what you want to do in production, right? You very often have five or 10 worker processes that are controlled by g unicorn or micro whiskey. And then they clone themselves for the to get the parallelism that you really would expect. Yeah, exactly. And that's precisely what I do with a official Docker image professed, epi just does that has unicorn, it runs unicorn, and then it runs your application. And it spawns the amount of processes if depending on the amount of processes available to the node that is running that Docker container. So you can just like create the Docker file, the basic Docker file, copy your app, and it shows like by default is fine tune to work pretty well. Yeah. If you use Docker, so yeah, like that, that'll probably be like the main combination, you will have unicorn with ubicomp running your application. But what if I do it wrong? And I hosted under straight g unicorn or I hosted under micro whiskey, both of which I don't think support as gi Not to my knowledge Anyway, what if I host it in something that is just a whiskey server, not a SGI server? What happens? It just won't work. It doesn't work at all. Okay, it probably just wouldn't work. Yeah, like if you have a server that only like a server provider, like a software as a service provider that only supports whiskey, that actually most of this servers nowadays, support ASCII. So you can actually use these frameworks very easily with most of these Software as a Service platforms. Or if you use something like I don't know, Google Cloud run, or any of these systems, there's actually a plugin, like an additional package that allows you to build fast API applications and run them as what is the name of this function services like lambdas? This server list? Right, right, right things. So you don't have to have a server running all the time. You can also like use these same tools and ideas and run them in one of these function providers. Oh, that's interesting. Yeah. Yeah. Cool. All right. Well, very cool project. Thanks for letting me do an a deep dive into it. Because I definitely think this is one of the shining examples of these new flowers and this next generation set of web frameworks that we talked about. So good job. Thank you very much for the invitation. It's been really great. Yeah, absolutely. Now, before we get out of here, though, I got to ask you the final two questions. Sure. If you're going to work on fast API, or what editor Do you use these days? So I'm currently using Visual Studio code. And they recently launched the new looking for Python, which is called pi lens. And it's really, really good. Yeah, that's my main eight are currently nice. And pi. Lance is a new language. Basically, it's the new Python plugin are built on top the other one, but it has a much better intelligence and visualization or understanding of like your whole project, and like the help strings and the type information and all that kind of stuff, right? So it's kind of levels up the autocomplete and the tooltips and whatnot. Exactly, because I was incomplete. And some of these things were pretty good with the previous plugin in Visual Studio code. These one uses another tool. It's old. It's actually written in TypeScript. But the thing is that it provides very good auto completion type checks and it has like the duration of death code. For example, if there's something some region in your code that will never be executed, if you're checking like, if false or something like that, it will detect that this section will never be executed. It also has a suit

01:00:00 Like it detects types very, very well, there are some advanced ways that you can declare type annotations. And that many, or at least the previous version of this editor and simulators, were not able to catch it very well. For example, when you use path live paths, the new plugin, get them very well, even when you do like sophisticated operations, including strings and things like that. So it actually works pretty pretty well. Very cool. Yeah. And I said, That's quite new. And then notable pi package. Obviously, there's pip install fast API. But you know, some package you've come across lately that you're like, Oh, you should definitely know about this. So I sort which is actually a common line package is one of the packages to do linting. And recently got a new release that I served is for doing automatic sorting of the imports in a file. Yeah. So you can I can be very sloppy in my code. And just import anywhere, I'm writing the code right on top of that version I just imported, and then I make it sort all the imports. So it's very nice and keeps the code very tidy. So that combined with black and other tools, it's great, but I think I sort deserves a lot more attention than it's getting right now. Very cool. Yeah, that's a nice one. All right, final call to action. People are interested in fast API, they want to get started, you know, how can they bring this into their maybe existing API s? Or create new IPS API's with it? What do you tell them? So I think the first thing is that I guess many people are like, hey, this seems kinda cool. I'm not sure if I'm into it. But maybe the first thing will be just to read the main page of the recommendation. And try the examples there is like, I don't know, it will take about 1015 minutes or something. And that's enough to know if you like it or not, that will be the main thing like Josie main page is enough to know if you like the things or not, if you don't like it, then you won't like it later.

01:01:53 And then the other thing is that some people, including me, get very excited about new frameworks and new tools and jump right ahead to refactor everything with the new shiny tool that we found, or something I have to tear it all down and rebuild it with is absolutely yeah, we rebuild it from scratch. Yeah. And it's normally not a very good idea, because you have some tool that is already tested, and it is already working. And if this new thing is not really providing a very huge benefit to the thing that is already there working, it's really not the best idea. What many teams do and what I actually have done in many occasions is to add a layer of us API on top of the current application, be it like, I don't know, Django rest framework, flask, or whatever, and then add the new features in this fast API application. And whenever I have to refactor something from the old application, then I just move it to fast API. So and then I just refactor it. But this thing is as fast API is doesn't have, like any compromise with database with the specific tools that you use for security or for session management or for anything, is actually compatible with all the other tools. And it's compatible with the database that you're having. And with the applications that we were really happy. So you can perfectly have both running at the same time. And then just separate, let's say, by the path that they are hunting. So everything that goes to API slash version one goes to flask and API slash version two goes to the new fast API application. I think that's a very good strategy that you work for many people when they want to add stuff. Cool. And the mechanics of that might be in nginx. Instead of just saying pass everything to this URL, you can say, pass everything to slash v1 slash to hear to this board or this socket, and then the other one over there and kind of behind the scenes, but at the front end, nobody knows. Yeah, exactly. You will do that with nginx. Or traffic. I really like traffic. And I use it for a bunch of things. It's also like hats, like automatic support for HTTPS certificates with Let's Encrypt, and it just keeps them makes sure that it's renewing them. So like it's a very nice system. And you can very easily say like, yeah, everything that goes to that specific path that goes to one side or the other. And you notice, there's also like h a proxy, and there's a bunch of folders that can that can do the job. And it's actually not that difficult to set up. And it will probably save you like a lot of headaches with deadlines that have not fulfilled, right. If you don't like it, you just switch it back. Yeah, exactly. Exactly. Yeah. Cool. Nevertheless, I have seen a bunch of teams that have been migrating the whole thing to fast API. Unfortunately, they have been happy about it. But yeah, I wouldn't suggest that as the main approach. They're cool. I guess it depends on the size of the project as well. Yeah, of course, of course. Yeah, for sure.

01:04:40 This has been another episode of talk Python. To me. Our guest on this episode was Sebastian Ramirez. And it's been brought to you by linode and Talk Python Training. Start your next Python project on the nodes state of the art cloud service. Just visit talk python.fm slash linode li n od e you'll automatically get a $20

01:05:00 credit when you create a new account, want to level up your Python. If you're just getting started, try my Python jumpstart by building 10 apps course. Or if you're looking for something more advanced, check out our new async course the digs into all the different types of async programming you can do in Python. And of course, if you're interested in more than one of these, be sure to check out our everything bundle. It's like a subscription that never expires. Be sure to subscribe to the show, open your favorite pod catcher and search for Python. We should be right at the top. You can also find the iTunes feed at slash iTunes. The Google Play feed is slash play in the direct RSS feed net slash RSS on talk python.fm. This is your host, Michael Kennedy. Thanks so much for listening. I really appreciate it. Don't get out there and write some Python code

Back to show page
Talk Python's Mastodon Michael Kennedy's Mastodon