WEBVTT

00:00:00.001 --> 00:00:04.880
As Python 3 has eclipsed the old constraints of Python 2 and the web frameworks that adopted them,

00:00:04.880 --> 00:00:08.360
we've seen a big jump in the new frameworks appearing on the scene,

00:00:08.360 --> 00:00:11.660
taking full advantage of things like type hints, async it away, and more.

00:00:11.660 --> 00:00:15.240
No framework has done this more successfully than FastAPI recently.

00:00:15.240 --> 00:00:18.840
That's why we're here with the creator of FastAPI, Sebastian Ramirez,

00:00:18.840 --> 00:00:21.700
to dive into this exciting new Python web framework.

00:00:21.700 --> 00:00:27.140
This is Talk Python To Me, episode 284, recorded July 23rd, 2020.

00:00:27.140 --> 00:00:43.840
Welcome to Talk Python To Me, a weekly podcast on Python,

00:00:43.840 --> 00:00:46.880
the language, the libraries, the ecosystem, and the personalities.

00:00:46.880 --> 00:00:48.820
This is your host, Michael Kennedy.

00:00:48.820 --> 00:00:50.960
Follow me on Twitter, where I'm @mkennedy.

00:00:50.960 --> 00:00:54.700
Keep up with the show and listen to past episodes at talkpython.fm,

00:00:54.700 --> 00:00:57.220
and follow the show on Twitter via at Talk Python.

00:00:57.220 --> 00:01:00.940
This episode is brought to you by Linode and us.

00:01:00.940 --> 00:01:05.820
Python's async and parallel programming support is highly underrated.

00:01:05.820 --> 00:01:09.180
Have you shied away from the amazing new async and await keywords

00:01:09.180 --> 00:01:13.220
because you've heard it's way too complicated or that it's just not worth the effort?

00:01:13.220 --> 00:01:18.820
With the right workloads, a hundred times speed up is totally possible with minor changes to your code.

00:01:19.200 --> 00:01:21.260
But you do need to understand the internals.

00:01:21.260 --> 00:01:24.700
And that's why our course, Async Techniques and Examples in Python,

00:01:24.700 --> 00:01:29.440
show you how to write async code successfully as well as how it works.

00:01:29.440 --> 00:01:35.360
Get started with async and await today with our course at talkpython.fm/async.

00:01:35.360 --> 00:01:38.220
Sebastian, welcome to Talk Python To Me.

00:01:38.220 --> 00:01:39.200
Thank you very much.

00:01:39.200 --> 00:01:40.800
Thank you for the invitation.

00:01:40.800 --> 00:01:42.240
It's a great pleasure to be here.

00:01:42.240 --> 00:01:44.320
Well, thanks for building a cool web API.

00:01:45.940 --> 00:01:47.000
You're welcome, I guess.

00:01:47.000 --> 00:01:49.520
Yeah, it's going to be fun to talk about it, actually.

00:01:49.520 --> 00:01:51.780
I think, you know, it's been really interesting.

00:01:51.780 --> 00:01:58.060
There were a lot of web frameworks that came out in 2005, 2008 timeframe.

00:01:58.060 --> 00:02:01.280
Then I feel like it kind of stabilized for a long time.

00:02:01.280 --> 00:02:03.420
And then I'm not sure exactly what it was,

00:02:03.420 --> 00:02:07.020
but I think that the async and await stuff coming along

00:02:07.020 --> 00:02:10.000
sort of pushed the creation of a bunch of new frameworks.

00:02:10.000 --> 00:02:12.920
And all of a sudden there was another framework every other week.

00:02:13.060 --> 00:02:14.000
It was crazy.

00:02:14.000 --> 00:02:17.660
And yours was kind of in that second wave or whatever wave that was.

00:02:17.660 --> 00:02:20.120
And yeah, it looks like it's getting a lot of traction.

00:02:20.120 --> 00:02:21.000
So that's awesome.

00:02:21.000 --> 00:02:22.020
Yeah, thank you very much.

00:02:22.020 --> 00:02:24.600
Yeah, I actually feel pretty much the same.

00:02:24.600 --> 00:02:29.120
I feel like there were like a couple of waves of frameworks and then a second one.

00:02:29.120 --> 00:02:33.000
And I was actually avoiding building a framework for a long time.

00:02:33.000 --> 00:02:33.900
Yeah.

00:02:33.900 --> 00:02:35.840
Yeah, I can imagine.

00:02:35.840 --> 00:02:37.160
I definitely want to ask you about that.

00:02:37.160 --> 00:02:38.420
But let's start with your story.

00:02:38.420 --> 00:02:39.620
How'd you get into programming in Python?

00:02:40.060 --> 00:02:44.740
So I'm not sure if I got to do some Python when I was little.

00:02:44.740 --> 00:02:49.700
But when I really got into it was in, I think, when I was 20 something,

00:02:49.700 --> 00:02:52.760
I was studying a bunch of courses online.

00:02:52.760 --> 00:02:55.620
And one of them was, I was doing a bunch of courses,

00:02:55.620 --> 00:02:58.480
actually doing everything in JavaScript on the browser,

00:02:58.480 --> 00:03:01.380
because Node.js was just starting to be something.

00:03:01.940 --> 00:03:06.020
And one of them required Python for doing artificial intelligence and stuff.

00:03:06.020 --> 00:03:08.960
And I ended up like, yeah, let's just try.

00:03:08.960 --> 00:03:10.340
Let's see if I can do it.

00:03:10.340 --> 00:03:15.060
And I ended up just like learning the basics of Python for the course.

00:03:15.060 --> 00:03:18.180
And it was super intense, but I ended up loving it.

00:03:18.180 --> 00:03:21.120
And yeah, I just went on with Python for everything.

00:03:21.120 --> 00:03:21.940
Oh, that's great.

00:03:21.940 --> 00:03:26.220
You know, Python is one of those things that learning Python is really interesting,

00:03:26.220 --> 00:03:29.820
because it's both super approachable, but kind of never ending.

00:03:29.820 --> 00:03:33.360
Like, I think one of the guests I had on not too long ago,

00:03:33.360 --> 00:03:38.160
I told a joke, talked about a t-shirt that was kind of a joke that said,

00:03:38.160 --> 00:03:39.280
I learned Python.

00:03:39.280 --> 00:03:41.720
It was a great afternoon or something like that, you know?

00:03:41.720 --> 00:03:42.840
Yeah.

00:03:43.080 --> 00:03:46.860
Which, in one hand, like, you can learn the syntax and you can make things happen

00:03:46.860 --> 00:03:48.800
or follow along in a simple example.

00:03:48.800 --> 00:03:52.280
But, you know, I'm still learning Python all the time, right?

00:03:52.280 --> 00:03:56.700
Like, learning about your framework, I learned a bunch of stuff that I needed to figure out,

00:03:56.700 --> 00:03:59.200
because it depends what you call Python.

00:03:59.200 --> 00:04:01.000
Do you call Python, is that the language?

00:04:01.000 --> 00:04:04.700
Or when you learn Python, are you also talking about learning the standard library?

00:04:04.700 --> 00:04:09.340
Or if you really want to blow it up, then like the stuff on PyPI, right?

00:04:09.340 --> 00:04:10.880
Like, you know, there's these different levels.

00:04:10.880 --> 00:04:13.100
And you hear people say, oh, I learned Python really quick.

00:04:13.100 --> 00:04:16.160
Or I've been learning Python for a long time and I'm still working on it.

00:04:16.160 --> 00:04:18.680
Those people are probably not talking about the same thing, right?

00:04:18.680 --> 00:04:19.760
Yeah, absolutely.

00:04:19.760 --> 00:04:24.140
And then you get into numerical computation and processing stuff on GPUs.

00:04:24.140 --> 00:04:29.040
And it's like a whole different story additional to everything else.

00:04:29.040 --> 00:04:29.940
Yeah, absolutely.

00:04:29.940 --> 00:04:30.260
Yeah.

00:04:30.260 --> 00:04:31.180
Oh, for sure.

00:04:31.180 --> 00:04:31.640
For sure.

00:04:31.640 --> 00:04:32.300
Yeah.

00:04:32.300 --> 00:04:34.540
And I only bring that up because I know there's a lot of people who are like

00:04:34.540 --> 00:04:36.100
learning Python and getting started.

00:04:36.100 --> 00:04:38.140
And they're probably a lot of times they're like,

00:04:38.140 --> 00:04:39.860
I'm still working on it after a year.

00:04:39.860 --> 00:04:40.580
You know what I mean?

00:04:40.640 --> 00:04:43.480
And I just, it's really interesting that people say the same thing.

00:04:43.480 --> 00:04:46.460
And there's like these layers that they're talking about.

00:04:46.460 --> 00:04:46.840
Cool.

00:04:46.840 --> 00:04:52.760
So you got into programming or Python dragged into the data science side of the world.

00:04:52.760 --> 00:04:53.280
That's cool.

00:04:53.280 --> 00:04:55.120
And what are you up to these days?

00:04:55.400 --> 00:04:58.700
So right now I'm working for Explosion in Berlin, Germany.

00:04:58.700 --> 00:05:03.760
Explosion are the creators of spaCy, the natural language processing package for doing things

00:05:03.760 --> 00:05:06.400
like machine learning over text.

00:05:06.400 --> 00:05:10.940
The Prodigy, the package for doing data annotation using active learning.

00:05:11.040 --> 00:05:12.040
So to annotate machine learning.

00:05:12.040 --> 00:05:13.040
So to annotate machine learning datasets.

00:05:13.040 --> 00:05:26.860
And think the deep learning library for doing, well, deep learning using ideas from functional programming, type annotations, and all these things in a way that is compatible with other tools like PyTorch, TensorFlow, etc.

00:05:27.120 --> 00:05:28.520
This is the company I'm working for.

00:05:28.520 --> 00:05:32.740
I'm working on the team that is building Prodigy Teams.

00:05:32.740 --> 00:05:44.700
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.

00:05:44.700 --> 00:05:52.540
But the important thing is that it runs on the client's cloud, on the specific company's cloud.

00:05:52.540 --> 00:05:58.400
So data is like stored and all the privacy stuff can be like safe and all the stuff.

00:05:58.400 --> 00:05:58.820
Yeah.

00:05:58.820 --> 00:06:03.360
So that's what I'm doing like mainly in Explosion from time to time.

00:06:03.360 --> 00:06:06.560
I also help put some extra things from the other projects.

00:06:06.560 --> 00:06:17.240
And as part like of, 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, I guess.

00:06:17.240 --> 00:06:17.560
Yeah.

00:06:17.560 --> 00:06:24.020
But yeah, like I get to spend like, I don't know, a fifth of all my working time just dedicated to this open source tool.

00:06:24.020 --> 00:06:26.880
So yeah, that's mainly my day to day flow.

00:06:26.880 --> 00:06:28.060
I know that sounds really fun.

00:06:28.060 --> 00:06:30.420
And yeah, Explosion AI seems like a cool company.

00:06:30.420 --> 00:06:33.920
You know, we just had Ines on Python Bytes on episode 191.

00:06:33.920 --> 00:06:37.920
So a little while ago when this ships, but you know, in calendar time, not long ago.

00:06:37.920 --> 00:06:38.480
Yeah.

00:06:38.480 --> 00:06:45.760
I'm guessing that you are probably using a lot of working a lot on the API side of that product, right?

00:06:45.760 --> 00:06:46.360
Exactly.

00:06:46.360 --> 00:06:46.760
Yeah.

00:06:46.760 --> 00:06:47.160
Yeah.

00:06:47.160 --> 00:06:48.320
Mainly on that side.

00:06:48.320 --> 00:06:48.820
Cool.

00:06:48.820 --> 00:06:51.300
Well, speaking of APIs, let's start there.

00:06:51.300 --> 00:06:54.760
Obviously, it's all about consuming APIs these days.

00:06:54.860 --> 00:06:55.720
APIs are everywhere.

00:06:55.720 --> 00:07:00.360
You go to Zapier and they're like, we integrate with, you know, however many thousand different

00:07:00.360 --> 00:07:02.680
API endpoints that you might want to work with.

00:07:02.680 --> 00:07:04.640
And it's, it's all pretty crazy.

00:07:04.640 --> 00:07:08.260
But of course, creating APIs is super important.

00:07:08.260 --> 00:07:14.820
So focusing on that side, how have you seen the evolution of API frameworks coming on?

00:07:14.880 --> 00:07:19.260
Because the early days that I spoke of, it was like things were web frameworks.

00:07:19.260 --> 00:07:23.980
And then if you wanted, you could somehow manage to put a web API in it.

00:07:23.980 --> 00:07:25.160
Yeah, absolutely.

00:07:25.160 --> 00:07:25.600
Exactly.

00:07:25.600 --> 00:07:27.300
I think that's the key difference.

00:07:27.300 --> 00:07:29.300
I think that's exactly the key difference.

00:07:29.300 --> 00:07:29.880
Yeah.

00:07:29.880 --> 00:07:30.600
Because.

00:07:30.600 --> 00:07:31.180
Yeah.

00:07:31.180 --> 00:07:35.260
So for example, this framework is basically, I don't know what you call it.

00:07:35.260 --> 00:07:37.500
I would think it was something like API first.

00:07:37.640 --> 00:07:41.040
I mean, obviously it's in the name, but there's a bunch of them like that these days that are

00:07:41.040 --> 00:07:46.880
coming out where it's the building blocks talk in terms of APIs, not in terms of web templates

00:07:46.880 --> 00:07:48.140
and whatnot.

00:07:48.140 --> 00:07:49.100
Yeah, exactly.

00:07:49.280 --> 00:07:54.940
So like, I guess for a very long time, the more established frameworks in Python specifically

00:07:54.940 --> 00:07:56.640
have been Flask and Django.

00:07:56.640 --> 00:08:00.940
And for APIs, it will be in Django, it will be Django REST framework.

00:08:00.940 --> 00:08:05.840
In Flask, there are a bunch of plugins that can be combined together to make something that

00:08:05.840 --> 00:08:07.040
works very well.

00:08:07.040 --> 00:08:08.820
The same as with Django REST framework.

00:08:08.820 --> 00:08:14.420
But the thing is that, as you were saying, these frameworks were made mainly to handle templates

00:08:14.420 --> 00:08:15.140
in the backend.

00:08:15.740 --> 00:08:22.840
So the extra plugins and the extra functionality was added on top around the ways that the framework

00:08:22.840 --> 00:08:24.240
was able to do things.

00:08:24.240 --> 00:08:31.000
So, and as you were saying, like there was this bunch of extra frameworks that came afterwards,

00:08:31.000 --> 00:08:34.380
like several, even at the same time, sort of.

00:08:34.380 --> 00:08:39.560
And then all the async wave came with a bunch of other frameworks.

00:08:39.560 --> 00:08:43.920
Past API ended up later in that last wave, I guess.

00:08:44.340 --> 00:08:48.520
But it was mainly from the learnings of all these previous frameworks.

00:08:48.520 --> 00:08:51.400
I was using a bunch of those frameworks for a long time.

00:08:51.400 --> 00:08:55.060
A bunch of plugins, a bunch of combinations, trying one thing, trying the other.

00:08:55.060 --> 00:08:59.820
I had like something that was kind of stable, but it's still very difficult to maintain and

00:08:59.820 --> 00:09:00.700
quite fragile.

00:09:00.700 --> 00:09:05.220
Yeah, you said that you didn't really want to build FastAPI, but finally you decided,

00:09:05.220 --> 00:09:07.780
all right, I need the thing I want to exist.

00:09:07.780 --> 00:09:08.580
So here we go.

00:09:08.580 --> 00:09:09.000
Yeah.

00:09:09.000 --> 00:09:12.540
I felt like the meme of, hey, I built another JavaScript framework.

00:09:12.540 --> 00:09:14.560
This happens like every week or so.

00:09:14.560 --> 00:09:17.520
And I was trying really hard to avoid that.

00:09:17.520 --> 00:09:22.240
And I was trying like, no, I just find the thing that I'm looking for and find the thing

00:09:22.240 --> 00:09:24.920
that will do the functionality that I need.

00:09:24.920 --> 00:09:25.200
Yeah.

00:09:25.440 --> 00:09:30.720
And at some point when I was like, yeah, I'm not finding the right thing.

00:09:30.720 --> 00:09:31.940
I found it.

00:09:31.940 --> 00:09:34.620
And it was API Star was the name.

00:09:34.620 --> 00:09:34.980
Right.

00:09:34.980 --> 00:09:41.280
API Star was a framework built by Tom Christie, a great guy, the same creator of Django REST

00:09:41.280 --> 00:09:41.580
framework.

00:09:41.580 --> 00:09:42.600
Yeah, exactly.

00:09:42.600 --> 00:09:45.280
A successor Django REST framework, but from scratch.

00:09:45.680 --> 00:09:46.680
Exactly, exactly.

00:09:46.680 --> 00:09:47.720
And that was API Star.

00:09:47.720 --> 00:09:51.960
And API Star was trying to be compatible with Woosgi and Asgi.

00:09:51.960 --> 00:09:58.080
So like the canonical standard specification or interface for web frameworks, which is what

00:09:58.080 --> 00:09:59.880
Flask and Django are based on.

00:09:59.880 --> 00:10:06.320
And at the same time with Asgi, which was the new standard that was also born at Django for

00:10:06.320 --> 00:10:09.060
doing web sockets and all these asynchronous things.

00:10:09.060 --> 00:10:09.540
Right.

00:10:09.540 --> 00:10:13.320
It's probably maybe worth just pointing out to the people listening who are not deep in

00:10:13.320 --> 00:10:19.780
the web hosting side, like Woosgi is this common API that all the different web frameworks,

00:10:19.780 --> 00:10:24.260
Flask, Django, and so on, can talk to or implement.

00:10:24.260 --> 00:10:29.840
And then all the web servers like uWSGI, GUnicorn, and so on, know how to talk to anything

00:10:29.840 --> 00:10:30.560
that does Woosgi.

00:10:30.560 --> 00:10:34.540
And that's how you can run all the different frameworks on these various web servers.

00:10:34.760 --> 00:10:39.940
But none of those were capable of supporting async programming, which is super important

00:10:39.940 --> 00:10:45.100
for scalability on the server side, because just the way that thing was written is incompatible

00:10:45.100 --> 00:10:45.560
with that.

00:10:45.560 --> 00:10:51.200
And so there's another standard, I think, yeah, maybe Tom was even partially involved in like

00:10:51.200 --> 00:10:56.040
defining the standard, I'm not sure, but called ASGI for async gateway interface.

00:10:56.040 --> 00:10:58.860
And that's the ASGI that you're talking about, right?

00:10:58.860 --> 00:11:01.900
So API Star was trying to do both of those things.

00:11:01.900 --> 00:11:02.740
Yeah, exactly.

00:11:02.740 --> 00:11:07.880
And complementing on what you were saying, like these specifications of how to interact

00:11:07.880 --> 00:11:11.680
with the server and the framework are actually like quite simple.

00:11:11.680 --> 00:11:13.780
It's mainly kind of one page.

00:11:13.780 --> 00:11:19.040
And it just says like, there has to be a function that is going to be called with these parameters.

00:11:19.040 --> 00:11:20.600
And it's basically that.

00:11:20.600 --> 00:11:24.940
But then defining what is the shape of that function, what are the parameters that it's going

00:11:24.940 --> 00:11:30.780
to receive, all that is like the main point of interaction between a server like Unicorn and

00:11:30.780 --> 00:11:32.680
a framework like Flask.

00:11:32.680 --> 00:11:41.220
So this new standard ASGI is the one that adds support for async and await and all these things.

00:11:41.220 --> 00:11:47.980
And API Star was trying to have support for both things while being an API first framework

00:11:47.980 --> 00:11:51.620
and having like a bunch of extra features that Tom Christie added.

00:11:51.840 --> 00:11:53.000
And it was great.

00:11:53.000 --> 00:11:59.320
I was just trying to add some authentication ideas to be able to integrate them with the

00:11:59.320 --> 00:12:00.420
API first things.

00:12:00.420 --> 00:12:07.180
And at that point, Tom Christie was also building Starlet, which is the micro framework slash toolkit

00:12:07.180 --> 00:12:11.760
for building APIs in ASGI, in this new building APIs.

00:12:11.760 --> 00:12:12.100
No, sorry.

00:12:12.100 --> 00:12:16.300
For building like web applications or for doing web stuff using this new standard.

00:12:16.640 --> 00:12:22.220
So it's like the bare bones thing is kind of in the middle of Flask and a lower level tool.

00:12:22.220 --> 00:12:23.940
It will do like kind of the same things.

00:12:23.940 --> 00:12:30.160
And because he was focusing on that, he had to deprecate most of the API Star components,

00:12:30.160 --> 00:12:36.520
like the server components, and made it just like a system and a set of tools to validate

00:12:36.520 --> 00:12:38.120
schemas for APIs.

00:12:38.120 --> 00:12:38.560
Right.

00:12:38.920 --> 00:12:43.440
And at that point, I just had found the perfect tool and then it had to be deprecated.

00:12:43.440 --> 00:12:45.420
So I guess that was the cue.

00:12:45.420 --> 00:12:48.520
That was the point where I said like, okay, let's try this.

00:12:48.520 --> 00:12:53.820
And at the same, you know, that is a little bit unfortunate, but at the same time, you now

00:12:53.820 --> 00:12:54.600
have Starlet.

00:12:54.600 --> 00:12:56.380
So you don't have to write that layer.

00:12:56.380 --> 00:12:58.080
You can work a little bit higher level.

00:12:58.080 --> 00:13:03.500
So, well, let me just put my take on an API for building APIs, a meta API.

00:13:04.340 --> 00:13:06.120
They're on top of Starlet, right?

00:13:06.120 --> 00:13:06.780
Exactly.

00:13:06.780 --> 00:13:07.160
Yeah.

00:13:07.160 --> 00:13:15.060
So Starlette is like one of the fastest or I guess the fastest framework for Python currently,

00:13:15.060 --> 00:13:17.480
like as measured by independent benchmarks.

00:13:17.480 --> 00:13:17.940
Right.

00:13:17.940 --> 00:13:20.180
TechEmpower is one of these people.

00:13:20.180 --> 00:13:20.620
Yeah, exactly.

00:13:20.620 --> 00:13:24.560
They measure not just, you're not saying that for Python frameworks, right?

00:13:24.560 --> 00:13:27.100
That's like a general statement for many of the web.

00:13:27.100 --> 00:13:30.760
They test all the different web frameworks, Python, Ruby, .NET, Java, and so on.

00:13:30.760 --> 00:13:31.740
Yeah, exactly.

00:13:31.740 --> 00:13:33.120
And a bunch of languages.

00:13:33.420 --> 00:13:35.960
And with a bunch of combinations of databases and stuff.

00:13:35.960 --> 00:13:37.140
So they have a great job.

00:13:37.140 --> 00:13:41.460
And they do like testing rounds on physical servers.

00:13:41.460 --> 00:13:46.820
So it's like a very, very robust and well-made general benchmark.

00:13:46.820 --> 00:13:52.400
So it's quite nice because lets you like see more clearly what are the things and the advantages

00:13:52.400 --> 00:13:52.940
and disadvantages.

00:13:52.940 --> 00:13:59.900
Of course, benchmarks are always somehow biased in one way or another and difficult to handle

00:13:59.900 --> 00:14:00.680
and to interpret.

00:14:01.160 --> 00:14:05.820
At least like it's a very common ground, I think, these ones.

00:14:05.820 --> 00:14:06.380
Right.

00:14:06.540 --> 00:14:11.140
So then Starlette was this new tool and it was built by Tom Christie, the same creator

00:14:11.140 --> 00:14:14.760
of Django REST framework, the same creator of the thing that I thought was the perfect

00:14:14.760 --> 00:14:16.200
match that I was looking for.

00:14:16.200 --> 00:14:20.060
So it was like a very, very solid option to build something on top.

00:14:20.060 --> 00:14:20.340
Yeah.

00:14:20.360 --> 00:14:22.280
I remember API Starlette being really nice.

00:14:22.280 --> 00:14:25.200
I was sad to see that it got semi-deprecated as well.

00:14:25.200 --> 00:14:25.720
Yeah.

00:14:25.720 --> 00:14:26.120
Yeah.

00:14:26.120 --> 00:14:27.440
I know.

00:14:27.440 --> 00:14:31.540
But I mean, if we have FastAPI, because I think that FastAPI is actually better.

00:14:31.540 --> 00:14:37.540
So it sounds to me like you're pretty happy with your job at Explosion AI, but you did have

00:14:37.540 --> 00:14:44.380
this, you did run across this interesting job ad asking and you sent out a tweet and oh my

00:14:44.380 --> 00:14:45.960
goodness, did that tweet take off.

00:14:45.960 --> 00:14:52.140
So it said that it was looking for somebody to work in FastAPI and it suggested that they

00:14:52.140 --> 00:14:54.240
have at least four years of experience with it.

00:14:54.240 --> 00:14:54.480
Right.

00:14:54.480 --> 00:14:55.860
Tell us about this.

00:14:56.860 --> 00:14:57.640
Yeah, exactly.

00:14:57.640 --> 00:15:04.000
It's fun because I thought like, huh, this is kind of a funny story.

00:15:04.000 --> 00:15:10.540
And actually I have seen several job posts requiring similar things like for FastAPI specifically

00:15:10.540 --> 00:15:14.680
requiring several years of FastAPI and FastAPI has one year and a half of existence.

00:15:14.680 --> 00:15:20.200
And I saw the job post and I was like, it's kind of fun, but not fun enough.

00:15:20.200 --> 00:15:22.700
But one day I was like, yeah, let's just tweet it.

00:15:22.700 --> 00:15:24.660
It's not really that fun, but whatever.

00:15:25.000 --> 00:15:32.000
So the tweet was, I saw a job post from four plus years of experience with FastAPI and

00:15:32.000 --> 00:15:36.300
I couldn't apply because I only have 1.5 years since I created that thing.

00:15:36.300 --> 00:15:43.340
I'm like, yeah, well, maybe it's time to reevaluate that years of experience is equal to the skill

00:15:43.340 --> 00:15:43.620
level.

00:15:43.620 --> 00:15:48.240
It was actually, I wrote it and I was like, it's not that fun.

00:15:48.240 --> 00:15:51.980
And I asked my wife and she said like, yeah, well, whatever, just post it.

00:15:51.980 --> 00:15:52.940
Yeah, exactly.

00:15:53.620 --> 00:15:54.940
Someone might find it fun.

00:15:54.940 --> 00:15:59.600
And then like two hours later, it was like 2000 likes or something like that.

00:15:59.600 --> 00:16:01.420
And it started growing like crazy.

00:16:01.420 --> 00:16:05.200
You probably almost had to like turn off notifications on your phone at that point.

00:16:05.200 --> 00:16:08.940
If it's just ding, ding, ding, ding, retweet, retweet, like retweet.

00:16:08.940 --> 00:16:11.040
Yeah, exactly.

00:16:11.040 --> 00:16:14.460
Like I tried to open the Twitter app in my phone.

00:16:14.540 --> 00:16:16.960
And for two days, it was just crashing immediately.

00:16:16.960 --> 00:16:18.320
It wouldn't even open.

00:16:18.320 --> 00:16:21.420
And I didn't even know, like, how is this thing?

00:16:21.420 --> 00:16:23.040
This is so weird.

00:16:23.040 --> 00:16:28.200
And if you see my Twitter account, you can see like the tweets before that or after that.

00:16:28.200 --> 00:16:29.140
Right, right, right, right.

00:16:29.140 --> 00:16:31.140
30 likes, 50 likes.

00:16:31.140 --> 00:16:33.060
Yeah, you really struck a nerve.

00:16:33.060 --> 00:16:33.680
Yeah.

00:16:33.680 --> 00:16:36.680
You really found like this idea of like, oh yeah.

00:16:36.680 --> 00:16:37.740
I guess so.

00:16:37.740 --> 00:16:40.380
We all hate this idea and it's all the time, right?

00:16:40.380 --> 00:16:41.580
Pretty funny.

00:16:41.580 --> 00:16:42.120
Yeah.

00:16:42.120 --> 00:16:42.720
Yeah.

00:16:42.720 --> 00:16:47.640
This portion of Talk Python To Me is brought to you by Linode.

00:16:47.640 --> 00:16:51.760
Whether you're working on a personal project or managing your enterprise's infrastructure,

00:16:51.760 --> 00:16:56.580
Linode has the pricing, support, and scale that you need to take your project to the next level.

00:16:56.580 --> 00:17:01.380
With 11 data centers worldwide, including their newest data center in Sydney, Australia,

00:17:01.380 --> 00:17:07.080
enterprise-grade hardware, S3-compatible storage, and the next-generation network,

00:17:07.080 --> 00:17:11.260
Linode delivers the performance that you expect at a price that you don't.

00:17:11.680 --> 00:17:16.700
Get started on Linode today with a $20 credit and you get access to native SSD storage,

00:17:16.700 --> 00:17:22.800
a 40 gigabit network, industry-leading processors, their revamped cloud manager at cloud.linode.com,

00:17:22.800 --> 00:17:27.300
root access to your server, along with their newest API and a Python CLI.

00:17:27.300 --> 00:17:33.400
Just visit talkpython.fm/Linode when creating a new Linode account and you'll automatically

00:17:33.400 --> 00:17:35.320
get $20 credit for your next project.

00:17:35.820 --> 00:17:36.620
Oh, and one last thing.

00:17:36.620 --> 00:17:37.400
They're hiring.

00:17:37.400 --> 00:17:40.500
Go to linode.com slash careers to find out more.

00:17:40.500 --> 00:17:41.860
Let them know that we sent you.

00:17:41.860 --> 00:17:45.840
Created about a year and a half ago.

00:17:45.840 --> 00:17:50.820
Let's talk about some of the core features because I really, really like the way that you put this

00:17:50.820 --> 00:17:51.180
together.

00:17:51.180 --> 00:17:56.280
It brings together two or three of my really favorite things about some of the language stuff.

00:17:56.400 --> 00:17:57.760
Type Annotations.

00:17:57.760 --> 00:18:04.120
It makes those like first class citizens in a, the right way to put it, a non-artificial way.

00:18:04.120 --> 00:18:10.260
Because I've seen people on other frameworks use Type Annotations, but the types are meant to talk to the

00:18:10.260 --> 00:18:12.620
framework, but they're not actually the types you end up with.

00:18:12.620 --> 00:18:14.360
You know, like think SQLAlchemy.

00:18:14.360 --> 00:18:17.720
Like you would say that by default, the type is a column type.

00:18:17.840 --> 00:18:19.320
But really what you mean is it's an integer.

00:18:19.320 --> 00:18:23.160
So, I mean, that's not SQLAlchemy doesn't do that, but there's some web frameworks that kind of have

00:18:23.160 --> 00:18:24.600
that similar take.

00:18:24.600 --> 00:18:27.940
So Type Annotations, the async and await stuff on the server.

00:18:27.940 --> 00:18:33.860
And then also this, this ability to have like a model that defines what you expect to be coming

00:18:33.860 --> 00:18:37.300
in and the ability to not have to do that juggling yourself.

00:18:37.300 --> 00:18:38.060
Yeah.

00:18:38.060 --> 00:18:38.460
Yeah.

00:18:38.460 --> 00:18:38.720
Yeah.

00:18:38.720 --> 00:18:39.040
Exactly.

00:18:39.140 --> 00:18:43.780
I think you, you already defined it better than me, but yeah, that was the idea.

00:18:43.780 --> 00:18:51.140
I wanted like coming from what I had seen on API star and with the idea that you could maybe

00:18:51.140 --> 00:18:56.180
add some extra information about the parameters that go into a function in the same declaration

00:18:56.180 --> 00:18:57.200
of those parameters.

00:18:57.200 --> 00:18:59.060
Then I wanted to extend that a bit.

00:18:59.060 --> 00:19:03.740
And that's when I found Pydantic, which is a library for doing data manipulation, which is

00:19:03.740 --> 00:19:07.480
awesome independently of if you use FastAPI or not.

00:19:07.580 --> 00:19:09.220
It's great by itself.

00:19:09.220 --> 00:19:15.540
And the way it works is that it's pretty much the same as with data classes, but it adds the

00:19:15.540 --> 00:19:19.020
additional data validation and data serialization.

00:19:19.020 --> 00:19:24.720
So if you type something that is declared with a type of an integer and you try to parse something

00:19:24.720 --> 00:19:30.040
that is not an integer, it will try to transform that into an integer and try to serialize that

00:19:30.040 --> 00:19:33.700
and convert that to the actual integer that you're declaring to receive.

00:19:33.700 --> 00:19:40.140
So for example, if you say that parameter in a, in a URL should be an integer, let's say the user ID,

00:19:40.140 --> 00:19:46.820
a Pydantic can take that and transform it into the, an actual integer so that the code internally

00:19:46.820 --> 00:19:48.420
receives an actual integer.

00:19:48.420 --> 00:19:48.980
Right.

00:19:48.980 --> 00:19:58.440
So FastAPI uses all these ideas from Pydantic and the internal tools to integrate that with the framework itself based all on top of Starlet.

00:19:58.440 --> 00:20:08.960
And as you say, I was trying to hit exactly that point of being able to use the type annotations in the standard way to use the standard type annotations.

00:20:08.960 --> 00:20:18.540
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 FastAPI or something,

00:20:18.600 --> 00:20:25.040
but just using the standard string as a type annotation and they get all the type support in the editor,

00:20:25.040 --> 00:20:32.960
like auto completion and type checks and all these things, having them by default working as it will be with any code base that is type annotated.

00:20:32.960 --> 00:20:37.680
So like all those features and on top of that, having the data validation,

00:20:37.680 --> 00:20:42.600
so that data is valid at the point that your code starts to run.

00:20:42.880 --> 00:20:46.720
You don't have to do all that validation by hand and data serialization.

00:20:46.720 --> 00:20:54.020
So for example, like with Pydantic, you can create, say, a user class and say it has an ID colon int and a name,

00:20:54.020 --> 00:20:55.680
which has a default value.

00:20:55.680 --> 00:21:01.500
And then another thing like a date time, which has an optional of, say, date time and so on.

00:21:01.500 --> 00:21:05.800
And if I'm reading it right, the ID that doesn't have any default value,

00:21:05.800 --> 00:21:08.400
but is also not an optional ID is a required field.

00:21:08.400 --> 00:21:10.800
Probably the name that has a default value.

00:21:10.800 --> 00:21:11.360
Exactly.

00:21:11.840 --> 00:21:14.500
Is optional and would take that default value.

00:21:14.500 --> 00:21:17.420
And the optional one that's explicit also would have an optional and so on.

00:21:17.420 --> 00:21:21.940
So like if there's a concrete type, it's both required and converted to that.

00:21:21.940 --> 00:21:26.940
If there's a default value, it is that type, but it's also, it's not required and so on.

00:21:26.940 --> 00:21:33.100
So there's a lot of nice nuance with almost nothing but like this field is this type and either is optional or not.

00:21:33.100 --> 00:21:33.320
Right?

00:21:33.320 --> 00:21:34.180
Yeah, exactly.

00:21:34.180 --> 00:21:40.140
And the idea is to like use the same, the same way that standard Python works.

00:21:40.400 --> 00:21:49.440
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.

00:21:49.440 --> 00:21:51.200
So it's interpreted that way.

00:21:51.400 --> 00:21:59.060
So the idea is that it just like hooks the standard intuition and uses that to provide all the extra features.

00:21:59.060 --> 00:22:03.860
So it should be just like very intuitive to work with and just work well by default.

00:22:03.860 --> 00:22:05.120
That's kind of the...

00:22:05.120 --> 00:22:06.260
It's beautiful.

00:22:06.260 --> 00:22:13.520
And then also because of the way that it's put together, it leverages all the stuff that tells the editors what to do.

00:22:13.520 --> 00:22:19.500
So if you get your value and you say, you know, dot, it knows what type that is and what to autocomplete right there.

00:22:19.880 --> 00:22:20.320
Exactly.

00:22:20.320 --> 00:22:20.360
Exactly.

00:22:20.360 --> 00:22:25.580
And because you can also have like very deeply nested and complex data structures.

00:22:25.580 --> 00:22:31.320
Like you can say that your API is going to receive a list of orders of food.

00:22:31.740 --> 00:22:38.820
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.

00:22:38.820 --> 00:22:44.540
So it's like a very nested and complex to even to explain a complex data structure.

00:22:44.740 --> 00:22:52.880
But then being able to have autocompletion, even for the deeply nested little bits inside of the editor and type checks and all that.

00:22:52.880 --> 00:22:56.180
Like for me, that's like, wow, this is so cool.

00:22:56.180 --> 00:22:57.780
It's so cool.

00:22:57.780 --> 00:22:59.820
And like, it's the fidantic that I use.

00:22:59.820 --> 00:23:00.200
Yeah.

00:23:00.200 --> 00:23:04.580
You know why it's so cool is because that's the part of programming that just sucks.

00:23:04.580 --> 00:23:07.840
Like you just, it's not fun to go, just go like, okay, does it have this?

00:23:07.840 --> 00:23:08.460
Does it have this?

00:23:08.460 --> 00:23:09.320
Is it this the type?

00:23:09.320 --> 00:23:10.180
I tried to convert it.

00:23:10.180 --> 00:23:10.740
No, it crashed.

00:23:10.740 --> 00:23:10.980
Okay.

00:23:11.040 --> 00:23:16.480
There's not much value in that, but you have to be very careful and specific.

00:23:16.480 --> 00:23:21.540
And just, if that could just go away like this and something else handles it, it's beautiful.

00:23:21.540 --> 00:23:23.360
Yeah.

00:23:23.360 --> 00:23:33.580
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.

00:23:33.580 --> 00:23:35.360
Like when you say, okay, let's build an API.

00:23:35.360 --> 00:23:38.060
Then you just add Flask and yeah, it works.

00:23:38.060 --> 00:23:44.920
But then you're not taking into account all the corner cases and all the invalid data problems and all those things.

00:23:44.920 --> 00:23:50.020
And it's very easy to miss that and to not realize that you have to validate all that stuff.

00:23:50.020 --> 00:23:56.600
So having something that kind of enforces you to do it and does it by default, that's, I guess, like the main benefit.

00:23:56.600 --> 00:23:56.980
Right.

00:23:56.980 --> 00:24:00.000
And so when that fails validation, what happens?

00:24:00.000 --> 00:24:04.620
Does the client get a 400 bad request with some kind of message about how it failed?

00:24:04.940 --> 00:24:05.500
Yeah, exactly.

00:24:05.500 --> 00:24:12.140
So when you declare, so let's say you create a class, a user class that inherits from this thing from Pydantic.

00:24:12.140 --> 00:24:16.960
And you say like, I'm going to receive a food that has a name and has some ingredients.

00:24:17.220 --> 00:24:24.440
And you declare the parameter inside of the function with using standard type annotations using the food colon.

00:24:24.440 --> 00:24:26.460
This is of an instance of this class food.

00:24:26.460 --> 00:24:32.120
So you have like standard Python type annotations and your code will be executed.

00:24:32.120 --> 00:24:40.700
Like the code inside of the function that will handle that request is going to be executed only after the data is validated.

00:24:40.940 --> 00:24:41.660
That's fantastic.

00:24:41.660 --> 00:24:52.640
So if someone sends, yeah, I think that's pretty cool because it saves like, I don't know, 20, 50 lines of code inside of each one of those functions that is just done automatically.

00:24:52.920 --> 00:25:04.780
So when data is invalid and it gets to the server, data is going to be validated and all the errors are going to be like checked and the client is going to receive.

00:25:04.780 --> 00:25:06.200
It's a 422 error.

00:25:06.200 --> 00:25:08.620
Yeah, it's a 400 range error.

00:25:08.620 --> 00:25:11.720
422 is the unprocessable entity.

00:25:11.980 --> 00:25:15.780
And it's going to tell the client exactly where is the error.

00:25:15.780 --> 00:25:20.200
So it's not only saying there's an invalid data in your request.

00:25:20.200 --> 00:25:32.380
It's 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.

00:25:32.380 --> 00:25:35.000
One of those ingredients is not really a string.

00:25:35.000 --> 00:25:36.960
So exactly there is a problem.

00:25:36.960 --> 00:25:37.580
Wow.

00:25:37.580 --> 00:25:38.580
Yeah, that's awesome.

00:25:38.580 --> 00:25:39.700
I love it.

00:25:39.760 --> 00:25:43.480
And you said it, but I'm not sure if it totally sunk in.

00:25:43.480 --> 00:25:51.680
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.

00:25:51.680 --> 00:25:55.720
So like it takes a food colon food and that's it.

00:25:55.720 --> 00:26:05.260
You don't have to like get from some dictionary and like copy it over or like FastAPI will look at that and say, oh, it's the thing that I have to supply this function or call it is this.

00:26:05.260 --> 00:26:07.380
So I'm going to take the posted JSON data.

00:26:07.540 --> 00:26:10.020
I'm going to run it through Pydantic, make sure everything works.

00:26:10.020 --> 00:26:19.360
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.

00:26:19.360 --> 00:26:19.560
Right?

00:26:19.560 --> 00:26:20.480
Yeah, exactly.

00:26:20.480 --> 00:26:20.920
Exactly.

00:26:21.100 --> 00:26:37.120
And if you're not going to do that, then you just won't receive it and the client will receive an error automatically.

00:26:37.120 --> 00:26:39.500
So it's just works by default.

00:26:39.700 --> 00:26:40.240
That's super cool.

00:26:40.240 --> 00:26:48.260
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, this is awesome.

00:26:48.260 --> 00:26:50.880
But it's nice is that it's API first.

00:26:50.880 --> 00:26:57.200
So if I was in, say, Flask, I would say at app.route, give it the URL.

00:26:57.380 --> 00:27:02.340
And then optionally, I could decide to filter down the HTTP verbs I could accept.

00:27:02.340 --> 00:27:07.420
I could say, is it methods equals get comma head or something like that, right?

00:27:07.420 --> 00:27:08.200
Those could be the things.

00:27:08.200 --> 00:27:08.600
Yeah.

00:27:08.780 --> 00:27:13.600
But with your API, it's app.get URL or app.post.

00:27:13.600 --> 00:27:21.000
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.

00:27:21.000 --> 00:27:21.900
Yeah, exactly.

00:27:21.900 --> 00:27:32.900
And the idea with that was that in many cases, it's very easy to end up having a bunch of logic to handle get and post in the same function.

00:27:32.900 --> 00:27:40.100
And then all that logic is actually like very cumbersome to untangle because it's handling different ideas and different cases.

00:27:40.100 --> 00:27:45.260
It might share some code, but it's mostly different ideas in most of the cases.

00:27:45.260 --> 00:27:46.700
Yeah, I've seen it too.

00:27:46.700 --> 00:27:47.940
And it's such a bad idea.

00:27:47.940 --> 00:27:55.080
It's like, why would you say if method equals get, here's part of my method, else if it's post, do this.

00:27:55.080 --> 00:28:00.060
Just make that two methods and just set the method, the verb to be the two things.

00:28:00.060 --> 00:28:05.500
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.

00:28:05.500 --> 00:28:06.740
This is the one that does the post.

00:28:06.740 --> 00:28:12.440
And it kind of, there's this cool concept of designing APIs or ways of consuming stuff that I like,

00:28:12.440 --> 00:28:15.960
like helping users fall into the pit of success.

00:28:15.960 --> 00:28:19.400
Like if you don't know what you're doing, you kind of bumble your way around.

00:28:19.400 --> 00:28:22.540
You're going to land into the place you should land.

00:28:22.540 --> 00:28:25.800
You got to fight to get out of that place to like do it wrong.

00:28:25.800 --> 00:28:26.340
You know what I mean?

00:28:26.340 --> 00:28:28.000
I hope so.

00:28:28.000 --> 00:28:28.820
I really hope so.

00:28:28.820 --> 00:28:30.920
And this helps people fall into the pit of success.

00:28:31.080 --> 00:28:39.760
And it's also that I waddled around into the neighboring places that didn't work very well.

00:28:39.760 --> 00:28:40.500
Yeah.

00:28:40.500 --> 00:28:47.740
And then like learning from these things, learning from all these best practices from different APIs, from different tools, from different plugins.

00:28:47.740 --> 00:28:51.820
It's like all that learning is what I try to put together with FastAPI.

00:28:51.940 --> 00:28:53.180
Yeah, well, well done, I think.

00:28:53.180 --> 00:29:06.000
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, Starlette itself has a bunch of cool features as well, right?

00:29:06.000 --> 00:29:07.100
Yeah, exactly.

00:29:07.100 --> 00:29:28.440
Starlette is, well, to start, FastAPI is actually kind of a thin, sort of thin layer on top of Starlet, adding the pydantic parts and combining it all together based on the standards, based on the open API, JSON schema, or two, all these standards from the web that you just like get by default when using, when creating a FastAPI application.

00:29:28.440 --> 00:29:33.320
But Starlette is the thing that is actually doing all the web handling.

00:29:33.320 --> 00:29:35.920
It's the thing that it provides all the performance.

00:29:35.920 --> 00:29:41.040
And Starlette has support for, so FastAPI also has support for web circuits.

00:29:41.040 --> 00:29:43.500
There's easy GraphQL integration.

00:29:43.500 --> 00:29:49.260
You can have templates the same as you would with Flask or with many other frameworks.

00:29:49.260 --> 00:30:00.480
So you can actually build a web application based on templates in the like same way as you will do with all their established frameworks.

00:30:00.480 --> 00:30:02.300
It's just that that's not where it shines.

00:30:02.840 --> 00:30:08.320
But yeah, like you can have all these different things by default just because it's based on Starlet.

00:30:08.320 --> 00:30:16.220
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 FastAPI?

00:30:16.220 --> 00:30:16.860
Yeah.

00:30:16.860 --> 00:30:21.500
Actually, I imagine you will have like a bunch of Jinja 2 templates or something like that.

00:30:21.560 --> 00:30:27.200
Then you can just preserve the same templates and you just reuse them and pass them to FastAPI.

00:30:27.200 --> 00:30:40.160
It's just that there's not that huge benefit from that because like the logic will end up being very similar and FastAPI won't provide a lot on top of what other frameworks made with templates will do.

00:30:40.160 --> 00:30:42.880
But yeah, you can actually do it fairly easily.

00:30:42.880 --> 00:30:43.380
Yeah.

00:30:43.380 --> 00:30:43.660
Okay.

00:30:43.660 --> 00:30:44.160
Yeah.

00:30:44.160 --> 00:30:49.060
I mean, we do have a bunch of APIs for like our mobile apps and stuff and it'd be nice to write those differently.

00:30:49.060 --> 00:30:49.700
Yeah.

00:30:49.700 --> 00:30:50.920
Yeah, absolutely.

00:30:50.920 --> 00:30:51.540
Yeah.

00:30:51.540 --> 00:30:51.840
Cool.

00:30:51.940 --> 00:30:59.060
So there's a bunch of features you get from Starlette and because this is a layer on top of that, you basically get all the features of Starlette Plus.

00:30:59.060 --> 00:31:02.120
We mentioned ASGI a couple of times.

00:31:02.120 --> 00:31:02.760
Yeah.

00:31:02.760 --> 00:31:08.820
And so I'm guessing I could do an async def view method or API endpoint.

00:31:08.820 --> 00:31:09.180
Yeah.

00:31:09.180 --> 00:31:12.620
So Starlette is based on this standard ASGI.

00:31:12.740 --> 00:31:27.620
So you actually can get like all the things that are compatible with ASGI and there's a bunch of tools and additional like middleware and things that you can integrate directly because it's based on one of these common standards.

00:31:27.620 --> 00:31:29.840
Like it's an open standard that everyone can implement.

00:31:29.840 --> 00:31:38.460
So you can add, I don't know, Sentry, you can add the Data Dog, you can add Elasticsearch, like the logging functionality.

00:31:39.020 --> 00:31:48.500
You can add like a bunch of things right there that are not necessarily even made for FastAPI or for Starlet, just because they adopt the same standard.

00:31:48.500 --> 00:31:50.700
You can get like all that as well.

00:31:50.700 --> 00:31:51.300
Okay.

00:31:51.300 --> 00:31:51.940
Super cool.

00:31:51.940 --> 00:31:53.780
And do you support async methods?

00:31:53.780 --> 00:31:55.040
Oh yeah, of course.

00:31:55.040 --> 00:32:01.240
So FastAPI is actually like mainly, well, and actually Starlette is mainly an async framework.

00:32:01.240 --> 00:32:05.020
So you will use async def for your functions.

00:32:05.220 --> 00:32:09.660
If you want to have like all the performance and you know how to use async and await.

00:32:09.660 --> 00:32:19.260
Async and await are like provide a bunch of performance and performance in concurrent scenarios, a bunch of performance benefits.

00:32:19.260 --> 00:32:25.140
But they have like their own ideas that you need to be aware of to be able to use them properly.

00:32:25.140 --> 00:32:30.160
So you need to be able to use tools that are compatible with async and await.

00:32:30.460 --> 00:32:35.160
So if you are using async and await, then you can take all the benefit from that.

00:32:35.160 --> 00:32:40.320
But with the Starlette and FastAPI, you can also use standard function definitions.

00:32:40.320 --> 00:32:48.260
And then it will do like the smart thing and will run those standard function definitions underneath in a thread pool.

00:32:48.480 --> 00:32:52.620
So the technical details is that it won't block the event loop.

00:32:52.620 --> 00:33:00.280
But the thing is that it won't degrade performance or it won't do something that actually ends up like hurting the whole application.

00:33:00.280 --> 00:33:10.080
So if you are not sure or if you are doing, I don't know, machine learning stuff, then you can just use a standard function definition with just def whatever.

00:33:10.720 --> 00:33:19.900
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 def functions.

00:33:19.900 --> 00:33:20.940
Oh, that's really nice.

00:33:20.940 --> 00:33:26.160
So you don't have to adopt the async APIs in order to work with it, but you can if you want to.

00:33:26.160 --> 00:33:27.080
Yeah, exactly.

00:33:27.200 --> 00:33:37.660
And for example, you can if you have a bunch of SQLAlchemy models with a Flask application or something else, then you can just reuse exactly the same SQLAlchemy models and reuse even the same database.

00:33:37.660 --> 00:33:45.300
So you can actually have both applications running at the same time and then just use a standard code as you would with normal def functions.

00:33:45.300 --> 00:33:46.060
Very nice.

00:33:46.060 --> 00:33:49.560
I think most people probably don't need that, right?

00:33:49.560 --> 00:33:53.680
Like most of the time, APIs are fast enough and they're just fine and whatnot.

00:33:53.880 --> 00:34:02.360
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 in Node.js or in Go.

00:34:02.360 --> 00:34:10.600
It is I just need to use a different thing, HTTP client that I'm consuming my API with like HTTPX or something that supports async.

00:34:10.600 --> 00:34:15.920
Or I need to use a slightly different ORM library that supports async await, right?

00:34:15.920 --> 00:34:19.520
Like a small adjustment rather than a throw it all away and start over.

00:34:20.060 --> 00:34:20.800
Exactly, exactly.

00:34:20.800 --> 00:34:24.280
And in fact, you can combine those in the same application.

00:34:24.280 --> 00:34:28.840
So you can have like a bunch of standard function definitions for most of the application.

00:34:28.840 --> 00:34:33.380
And then you need one that needs to have like all the maximum possible performance.

00:34:33.380 --> 00:34:42.340
You can have like, I don't know, maybe literal SQL statements connected to an async postgres driver or something.

00:34:42.340 --> 00:34:48.680
And then do that only for that specific endpoint that needs to have like all the maximum performance.

00:34:48.680 --> 00:34:51.160
And then the rest, you can just do the standard code.

00:34:51.360 --> 00:34:51.420
Right.

00:34:51.420 --> 00:35:04.880
And in FastAPI, there's a dependency injection system that can be used to handle data positions and a bunch of things, but also to do things like authentication, authorization, getting, for example, getting the current user from a request, things like that.

00:35:04.880 --> 00:35:09.300
And it's all gets integrated into the automatic user interface that is generated.

00:35:09.300 --> 00:35:17.920
But the cool thing is that you can actually combine async and normal function definitions for these dependencies that can depend on one another.

00:35:17.920 --> 00:35:26.760
So you can have different async and normal function definitions even for the same route that you're handling, even for the same endpoint.

00:35:26.760 --> 00:35:27.600
Oh, wow.

00:35:27.600 --> 00:35:28.260
Okay.

00:35:28.260 --> 00:35:29.320
That's pretty awesome.

00:35:29.320 --> 00:35:34.180
Talk Python To Me is partially supported by our training courses.

00:35:34.640 --> 00:35:37.200
How does your team keep their Python skills sharp?

00:35:37.200 --> 00:35:41.340
How do you make sure new hires get started fast and learn the Pythonic way?

00:35:41.340 --> 00:35:50.320
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.

00:35:50.320 --> 00:35:54.240
At Talk Python Training, we have enterprise tiers for all of our courses.

00:35:54.240 --> 00:35:58.780
Get just the one course you need for your team with full reporting and monitoring.

00:35:59.120 --> 00:36:06.500
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.

00:36:06.500 --> 00:36:13.800
For details, visit training. talkpython.fm/business or just email sales at talkpython.fm.

00:36:15.580 --> 00:36:20.780
One thing I think would be fun to do is maybe compare this to Flask at an API level.

00:36:20.780 --> 00:36:22.000
And there's a cool article.

00:36:22.000 --> 00:36:22.440
I don't know.

00:36:22.440 --> 00:36:23.040
Have you seen it?

00:36:23.040 --> 00:36:25.720
This article called FastAPI for Flask users?

00:36:25.720 --> 00:36:27.000
Yeah, yeah, yeah.

00:36:27.000 --> 00:36:28.200
It got a lot of attention.

00:36:28.200 --> 00:36:32.960
And it was actually very on point with most of the things like how they are different.

00:36:32.960 --> 00:36:33.520
Yeah.

00:36:33.520 --> 00:36:34.680
And the advantages and stuff.

00:36:34.680 --> 00:36:35.180
Yeah.

00:36:35.180 --> 00:36:37.600
So this is an article by Amit Chantari.

00:36:37.600 --> 00:36:38.820
I'll link to it.

00:36:39.000 --> 00:36:41.480
But basically, he goes through and says, all right, you know Flask.

00:36:41.480 --> 00:36:46.280
Here's what you would do if you were to convert your app or rewrite it or just learn FastAPI.

00:36:46.280 --> 00:36:49.460
And I think a lot of people out there know the API for Flask.

00:36:49.460 --> 00:36:51.520
So I think it'll be a quick comparison.

00:36:51.520 --> 00:36:59.500
So the first one that we talked about a little bit is that this is API first, not page first or URL destination first.

00:36:59.500 --> 00:37:04.100
So instead of app.route, you have app.get, app.post, and so on.

00:37:04.100 --> 00:37:05.640
And pass the URL, of course.

00:37:05.640 --> 00:37:06.800
That's what we talked about.

00:37:06.800 --> 00:37:12.800
I think one that touches on some of the stuff, some of the advantages are you've got app.route.

00:37:12.800 --> 00:37:15.880
And then you can specify a variable in there.

00:37:15.880 --> 00:37:22.260
And in Flask, it's nice as well that you can say this variable is an integer or it is float or something.

00:37:22.260 --> 00:37:25.620
And it'll look at that and it'll require it to be an integer.

00:37:25.620 --> 00:37:28.360
And it will cast it to an integer and then pass it to you, right?

00:37:28.360 --> 00:37:28.620
Yeah.

00:37:28.800 --> 00:37:30.740
But in your framework, you just say there's a variable.

00:37:30.740 --> 00:37:34.160
And in the function, you say it's an integer, which I think is better.

00:37:34.160 --> 00:37:40.000
I mean, it's sort of equivalent, but it's better because the tooling, mypy, PyCharm, VS Code,

00:37:40.000 --> 00:37:41.320
they all know that it's an integer.

00:37:41.320 --> 00:37:44.160
Whereas the Flask version, it just happens to be.

00:37:44.160 --> 00:37:44.720
Yeah.

00:37:44.720 --> 00:37:50.200
So the thing is that Flask was made in the Python 2.something versions.

00:37:50.200 --> 00:37:59.180
So it's a great syntax and some great ideas that used the available options that were there at the time.

00:37:59.180 --> 00:38:04.640
But then the thing is that you end up having to learn this extra syntax of where to put,

00:38:04.640 --> 00:38:10.320
like what is the type and what is the variable and what is the symbol that you have to put on the size.

00:38:10.560 --> 00:38:15.700
There's like a little extra syntax that is specific to Flask that you have to learn.

00:38:15.700 --> 00:38:21.680
The idea here was to use the same concepts that are like now part of Python itself.

00:38:21.680 --> 00:38:24.960
So for example, to declare a variable, you don't use, how do you call them?

00:38:24.960 --> 00:38:28.400
Like angular braces or like less than and more than?

00:38:28.900 --> 00:38:29.560
Yeah, exactly.

00:38:29.560 --> 00:38:29.920
Yeah, yeah.

00:38:29.920 --> 00:38:30.400
Angle brackets.

00:38:30.400 --> 00:38:30.640
Yeah.

00:38:30.640 --> 00:38:31.120
Yeah.

00:38:31.120 --> 00:38:34.840
You use call the braces, which is the same one that you use for f-strings.

00:38:34.840 --> 00:38:37.480
So it should be relatively familiar.

00:38:37.480 --> 00:38:37.980
Yeah.

00:38:37.980 --> 00:38:40.500
And then to declare the type is just like in the function,

00:38:40.500 --> 00:38:44.600
which you will probably want to declare the type in the function either way,

00:38:44.600 --> 00:38:46.920
even if you were using Flask instead of FastAPI,

00:38:46.920 --> 00:38:50.460
just to get like all the type support from the editor and from tools.

00:38:50.460 --> 00:38:50.900
So.

00:38:50.900 --> 00:38:51.420
Exactly.

00:38:51.420 --> 00:38:52.180
That's what I do.

00:38:52.180 --> 00:38:54.040
But you've got to have it in two places, right?

00:38:54.040 --> 00:38:58.360
You got to have it in the route definition and in the function parameter.

00:38:58.360 --> 00:39:00.340
And they could get out of sync, which is annoying.

00:39:00.340 --> 00:39:03.920
I mean, this is not a huge bash on Flask type of thing.

00:39:03.920 --> 00:39:06.960
Like you said, it just predated the concept of type annotation.

00:39:06.960 --> 00:39:07.700
Yeah.

00:39:07.700 --> 00:39:12.560
And actually like a lot of the things in FastAPI were learned from Flask

00:39:12.560 --> 00:39:16.600
and from a bunch of additional plugins that were compatible with Flask,

00:39:16.600 --> 00:39:22.080
including Marshmallow and WebArgs and Flask API spec that were great tools.

00:39:22.080 --> 00:39:26.900
And those were my favorite tools like up until I built FastAPI to be able to have like

00:39:26.900 --> 00:39:33.340
that functionality that they provided, but like taking the advantage of the new type of notations.

00:39:33.340 --> 00:39:40.700
But yeah, it's like FastAPI wouldn't exist if it was not for the learnings provided by all these previous tools.

00:39:40.700 --> 00:39:41.780
Yeah, for sure.

00:39:41.780 --> 00:39:45.960
Another one, query strings and maybe more general, right?

00:39:45.960 --> 00:39:54.280
Like if I understand it right, FastAPI will take the data from all the places it is provided to your endpoint, right?

00:39:54.280 --> 00:40:00.140
So obviously if you post a JSON document or a form, it'll take it from there and put it into your argument,

00:40:00.140 --> 00:40:04.500
but also from the query string, from the headers, from the cookies and so on, right?

00:40:04.500 --> 00:40:10.940
Yeah. So basically the way that you declare that you, let's say in many traditional frameworks,

00:40:10.940 --> 00:40:18.880
you receive a request, a request object, or you import in some way, you have some type of request object.

00:40:18.880 --> 00:40:24.440
And from the request object, you extract data, you get JSON data, you get query parameters,

00:40:24.440 --> 00:40:27.340
you get path parameters, cookies, whatever.

00:40:27.600 --> 00:40:31.600
But you start with a request that is the same for all your functions.

00:40:31.600 --> 00:40:37.940
In FastAPI, you can actually get the request and get the data by yourself directly if you want to do so.

00:40:37.940 --> 00:40:39.600
So it's actually also available.

00:40:39.600 --> 00:40:46.220
But the main point of interaction and the main point of extracting the data is not getting a request object,

00:40:46.220 --> 00:40:49.480
but declaring the parameters in the function.

00:40:49.480 --> 00:40:53.980
And those parameters will be extracted, validated, and everything from the request.

00:40:54.300 --> 00:40:57.840
And also documented, because when you create an application with FastAPI,

00:40:57.840 --> 00:41:03.600
you get automatic API documentation in a web user interface that you can explore and use interactive.

00:41:03.600 --> 00:41:09.560
So like the main point of information extraction is in those parameters in the function.

00:41:09.560 --> 00:41:11.880
Yeah. And what happens if it's missing, right?

00:41:11.880 --> 00:41:14.540
Like a query string is something that may or may not be there.

00:41:14.540 --> 00:41:19.160
Yeah. For example, let's say that you have a query string that you call like,

00:41:19.160 --> 00:41:24.360
Yeah, well, Q because it's you are doing some query search or something.

00:41:24.360 --> 00:41:25.480
If you declare...

00:41:25.480 --> 00:41:30.060
Right, right. So you'd have like endpoint question mark Q equals some value you want to search for.

00:41:30.060 --> 00:41:31.460
Yeah, exactly. Exactly.

00:41:31.460 --> 00:41:35.280
Then you declare the function and you add a parameter that is called Q.

00:41:35.280 --> 00:41:43.980
Because the parameter is called Q, the FastAPI will look for a parameter in the query that is also called Q.

00:41:44.280 --> 00:41:47.160
Then you declare a type for that parameter.

00:41:47.160 --> 00:41:49.600
Let's say it's a string because we want text string.

00:41:49.600 --> 00:41:52.120
So FastAPI will make sure that it's a string.

00:41:52.120 --> 00:41:54.480
Well, given it's a URL, it will always be a string.

00:41:54.480 --> 00:41:57.800
But you could say like it's a boolean and FastAPI will make sure that it's a boolean.

00:41:57.800 --> 00:41:58.120
Right.

00:41:58.120 --> 00:42:00.860
But then you can also say, hey, this thing is optional.

00:42:00.860 --> 00:42:03.880
So by default, this will be none.

00:42:04.440 --> 00:42:16.520
So that means FastAPI, like in the Python world with like independent of FastAPI, when you declare a function that has a default value, then that parameter automatically is not required.

00:42:16.520 --> 00:42:22.240
So FastAPI will use that same logic and make the parameter not required because it has a default value.

00:42:22.240 --> 00:42:34.120
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.

00:42:34.120 --> 00:42:42.840
You could have default values for those query parameters and say like that the default value is to skip zero because you want to get all the users from the first one.

00:42:42.840 --> 00:42:45.340
And the limit is by default 10.

00:42:45.340 --> 00:42:45.780
Right.

00:42:45.780 --> 00:42:53.600
But then you will get those values in your code, but the user provides them in the query parameters, then FastAPI will read that from those query parameters.

00:42:53.600 --> 00:43:01.280
So you actually use the same ideas that you use in normal functions to declare when something is required or not.

00:43:01.280 --> 00:43:03.060
Like this is the basic case.

00:43:03.060 --> 00:43:11.580
There's an additional case where you want to do additional data validation of those specific query parameters on those specific data that you're receiving.

00:43:11.760 --> 00:43:17.880
For example, you want to make sure that the query is not longer than 100 characters or something like that.

00:43:17.880 --> 00:43:20.740
You can do additional validation for that with another technique.

00:43:20.740 --> 00:43:26.600
But in the basic case, it's just like the same way you use for standard functions.

00:43:26.600 --> 00:43:27.080
Right.

00:43:27.080 --> 00:43:36.880
Like if you wanted more validation, you could have a search parameters, Pydantic type, could have a field queue, and then you could put the Pydantic requirements and restrictions there.

00:43:36.880 --> 00:43:37.080
Right.

00:43:37.080 --> 00:43:37.120
Right.

00:43:37.120 --> 00:43:37.560
Yeah.

00:43:37.560 --> 00:43:46.540
And actually, like FastAPI will, if you declare a parameter that has a simple type like a string or a boolean or something like that, FastAPI will try to read it from the query.

00:43:46.660 --> 00:43:56.420
But if you want to read it from, let's say, from a cookie, then you can import another utility from FastAPI and make the default value of that parameter.

00:43:56.420 --> 00:44:07.020
That thing that you imported, which is a function, and you just call it, and that tells FastAPI, hey, I want this thing to be retrieved from the cookie, not from the query that will be the default.

00:44:07.400 --> 00:44:07.920
Right, right.

00:44:07.920 --> 00:44:09.700
That's a really interesting angle as well.

00:44:09.700 --> 00:44:21.000
So because my stuff is in Pyramid, and 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.

00:44:21.000 --> 00:44:21.320
Yeah.

00:44:21.320 --> 00:44:24.540
What's really annoying about when you're giving the request is it's not just like here's the data.

00:44:24.540 --> 00:44:25.380
It's like, no, no, no.

00:44:25.380 --> 00:44:27.920
There's a JSON body thing you've got to go check.

00:44:27.920 --> 00:44:31.160
There's a form you've got to check.

00:44:31.160 --> 00:44:33.000
There's the query string you've got to check.

00:44:33.000 --> 00:44:33.660
There's the headers.

00:44:33.660 --> 00:44:36.540
There's all these different dictionaries you've got to go check, right?

00:44:36.860 --> 00:44:47.960
So what I've done so far is I've just I've set up some sort of lower level infrastructure that like, we'll just take that and merge it all into one giant dictionary and go, here's the data you've been provided.

00:44:47.960 --> 00:44:49.100
You can ask for it.

00:44:49.100 --> 00:44:56.120
You know, the form has or the URL has higher priority than the form, which has higher priority than like, you know, query string and all those kinds of things.

00:44:56.120 --> 00:44:56.340
Right.

00:44:56.340 --> 00:44:56.800
Yeah.

00:44:56.800 --> 00:44:58.080
But yeah, this is nicer.

00:44:58.080 --> 00:45:02.380
I'm glad you like it.

00:45:02.380 --> 00:45:03.080
Yeah, for sure.

00:45:03.080 --> 00:45:07.500
But yeah, it's actually it's one of those things that everyone ends up having a taste.

00:45:07.500 --> 00:45:12.820
And sometimes people come like, hey, why are you doing it this way and not that way that I prefer?

00:45:12.820 --> 00:45:17.200
And it's like, well, yeah, like I had to make some decisions and have some defaults.

00:45:17.200 --> 00:45:21.500
But you can actually customize it to have whatever you actually want.

00:45:21.500 --> 00:45:24.900
One of the things I think the API is a lot like Flask.

00:45:24.960 --> 00:45:27.360
And I think Flask is a very popular framework.

00:45:27.360 --> 00:45:30.820
But what's even more popular is the basic API of Flask.

00:45:30.820 --> 00:45:34.440
Like you look at Sanic and it's kind of Flask like you look at Responder.

00:45:34.440 --> 00:45:36.240
It's kind of Flask like, you know what I mean?

00:45:36.240 --> 00:45:40.840
Like, yeah, this idea of I create an app and then I do app dot route or something to the equivalent.

00:45:40.840 --> 00:45:42.300
It's just super popular.

00:45:42.300 --> 00:45:42.640
Right.

00:45:42.640 --> 00:45:51.080
One of the drawbacks of that API and maybe the cute little demos of like, look, you can in like 10 lines of code, write your web server.

00:45:51.080 --> 00:45:51.860
And it's all great.

00:45:51.860 --> 00:45:59.780
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.

00:45:59.780 --> 00:46:06.220
So I guess every single one of my API or view methods just goes into like the main app dot PY file.

00:46:06.220 --> 00:46:06.540
Right.

00:46:06.540 --> 00:46:13.800
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.

00:46:13.800 --> 00:46:14.220
Right.

00:46:14.220 --> 00:46:14.840
You just use that.

00:46:14.840 --> 00:46:18.820
And in a real app, you would be hurting if you put that.

00:46:18.980 --> 00:46:24.700
I mean, there's hundreds of API and for web endpoints in my apps.

00:46:24.700 --> 00:46:27.440
And you want to put those into different modules.

00:46:27.440 --> 00:46:28.060
Right.

00:46:28.060 --> 00:46:30.980
Like, oh, here's where I deal with like, see your food example.

00:46:30.980 --> 00:46:32.600
Here's how I deal with the recipes.

00:46:32.600 --> 00:46:35.880
Here's how I go and get like a particular thing for the food.

00:46:35.880 --> 00:46:38.060
Here's how I get like my preferences.

00:46:38.060 --> 00:46:39.560
Like those are not all the same place.

00:46:39.560 --> 00:46:39.780
Right.

00:46:39.980 --> 00:46:40.260
Yeah.

00:46:40.260 --> 00:46:49.880
So if Flask has blueprints, what does FastAPI have for the ability to factor your code into what I would call real applications?

00:46:50.440 --> 00:46:54.780
So FastAPI has this additional tool, very similar to blueprints.

00:46:54.780 --> 00:47:01.420
Actually, if you search for blueprint, Flask blueprints in FastAPI, you get immediately to the docs on how to do that.

00:47:01.420 --> 00:47:08.400
There's this additional class comparable to the FastAPI class that you use to create an app that is called API router.

00:47:08.400 --> 00:47:18.020
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.

00:47:18.020 --> 00:47:22.480
But then you just have like, I don't know, router.get and the URL that you want.

00:47:23.040 --> 00:47:28.760
And then you can import all those routers in your main application and include them in the main application.

00:47:28.760 --> 00:47:31.840
And you can actually include them adding a prefix for the path.

00:47:31.840 --> 00:47:36.320
So you can have like, let's say, one module, one Python file for users.

00:47:36.320 --> 00:47:42.260
And then you have just router.get slash without even having to declare slash users slash.

00:47:42.260 --> 00:47:44.400
You just say router.get slash.

00:47:44.400 --> 00:47:46.480
And then it will provide you all the users.

00:47:46.720 --> 00:47:56.080
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 slash users slash.

00:47:56.080 --> 00:47:57.380
Yeah, that's fantastic.

00:47:57.380 --> 00:48:04.680
Because that's usually the thing that tells you how you want to break up your endpoints and group them, right?

00:48:04.680 --> 00:48:06.740
Like, here's all the stuff that slash admin.

00:48:06.740 --> 00:48:09.400
Here's all the stuff that is slash users and so on.

00:48:09.400 --> 00:48:11.800
And you just enforce it right that way as well.

00:48:11.800 --> 00:48:12.200
That's great.

00:48:12.200 --> 00:48:13.020
Yeah, exactly.

00:48:13.020 --> 00:48:13.420
Exactly.

00:48:13.420 --> 00:48:15.760
So it's actually quite simple to do.

00:48:15.900 --> 00:48:19.160
And you can like structure the application in a very simple way.

00:48:19.160 --> 00:48:21.440
It's actually part of the main documentation.

00:48:21.440 --> 00:48:26.720
Documentation is structured in a way that is a user guide and at the same time kind of reference.

00:48:26.720 --> 00:48:35.320
But it's made in a way that you can go one point after the other and get like a full system with all the basic stuff.

00:48:35.320 --> 00:48:38.980
And there's another section with all the extra advanced stuff.

00:48:39.380 --> 00:48:49.920
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 all work together.

00:48:50.200 --> 00:48:50.500
Yeah.

00:48:50.500 --> 00:48:51.340
Yeah, cool.

00:48:51.340 --> 00:49:01.960
Another thing that is common around APIs is not very common around websites, but is quite common around APIs is you need to document what are the endpoints?

00:49:02.620 --> 00:49:04.460
What are the expected values?

00:49:04.460 --> 00:49:06.740
Like your JSON documents look like this.

00:49:06.740 --> 00:49:07.560
This is required.

00:49:07.560 --> 00:49:08.300
It's an integer.

00:49:08.300 --> 00:49:09.220
This is optional.

00:49:09.220 --> 00:49:10.700
It's a date time and so on.

00:49:10.700 --> 00:49:12.020
What's the story for that here?

00:49:12.360 --> 00:49:21.840
So I guess I suffer from that maintaining corporate wikis that always got obsolete and the front end team came fighting like, hey, this thing doesn't work.

00:49:21.840 --> 00:49:23.640
Like, no, it was updated a week ago.

00:49:23.640 --> 00:49:30.660
So when you create an application with FastAPI, FastAPI itself is all built around open standards.

00:49:31.000 --> 00:49:39.260
So when you create an application with FastAPI, you get an API that is based on standards and you get an open API schema.

00:49:39.260 --> 00:49:40.860
So the standard is called open API.

00:49:40.860 --> 00:49:47.900
And you get a schema, which is just a very big JSON that the clarion describes everything in your API.

00:49:47.900 --> 00:49:50.640
All the paths, all the parameters, everything.

00:49:50.640 --> 00:50:05.400
This is a big JSON that you actually kind of never look at because this JSON is read by a user interface that you can see through the web browser that documents all your API and that you can explore and actually interact with it live.

00:50:05.400 --> 00:50:13.060
So you get automatic interactive documentation in your web browser included by default when you create an application.

00:50:13.060 --> 00:50:14.220
And you can use it.

00:50:14.220 --> 00:50:19.260
It's fun because sometimes people ask me, like, who is the user of that user interface?

00:50:19.760 --> 00:50:23.720
And like, when you start this, like, you assume like no one is going to use it.

00:50:23.720 --> 00:50:29.740
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.

00:50:29.740 --> 00:50:31.840
The front end team that you have to communicate.

00:50:31.840 --> 00:50:36.280
And then you yourself end up using it to see like, hey, is this thing working or not?

00:50:36.280 --> 00:50:38.440
So you actually end up using it a lot.

00:50:38.440 --> 00:50:38.940
Exactly.

00:50:38.940 --> 00:50:41.480
Or what does the system think?

00:50:41.480 --> 00:50:43.540
I told it I want, right?

00:50:43.540 --> 00:50:46.240
Does it, does it think this is optional or not optional?

00:50:46.240 --> 00:50:47.120
I want it to be optional.

00:50:47.120 --> 00:50:47.920
What does it say?

00:50:47.920 --> 00:50:49.140
Yeah, exactly.

00:50:49.340 --> 00:50:49.700
Exactly.

00:50:49.700 --> 00:51:02.180
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.

00:51:02.180 --> 00:51:03.700
It's all generated automatically.

00:51:03.700 --> 00:51:06.740
You don't have to do any effort to get that.

00:51:06.740 --> 00:51:10.960
Like just by writing your standard code, you get that kind of for free.

00:51:10.960 --> 00:51:14.480
So that's really helpful when developing and when using.

00:51:14.860 --> 00:51:15.460
Yeah, for sure.

00:51:15.460 --> 00:51:21.400
If I were to put a doc string that just was like a summary of what happens, would that show up in the documentation?

00:51:21.400 --> 00:51:22.560
Yeah, exactly.

00:51:22.560 --> 00:51:30.840
The doc string will end up in the documentation, in the interactive documentation, and you can actually use markdown and it will be rendered as a markdown.

00:51:30.840 --> 00:51:31.660
Oh, sweet.

00:51:32.020 --> 00:51:33.260
So yeah, it works.

00:51:33.260 --> 00:51:34.000
As it should.

00:51:34.000 --> 00:51:34.440
Awesome.

00:51:34.440 --> 00:51:34.480
Awesome.

00:51:34.480 --> 00:51:35.000
Yeah.

00:51:35.000 --> 00:51:35.080
Yeah.

00:51:35.080 --> 00:51:37.200
That works pretty well.

00:51:37.200 --> 00:51:41.820
Well, and you also have like the utilities to document each of the things that you declare.

00:51:41.820 --> 00:51:50.340
Like if you declare one of these classes that we were mentioning, you can have documentation for that specific class, which will be like a JSON payload.

00:51:50.340 --> 00:51:52.700
It could have its own description.

00:51:52.700 --> 00:51:56.040
Like each one of the fields could have its own description.

00:51:56.040 --> 00:52:00.680
Like you can say name, this refers to the name of the food that you are requesting or whatever.

00:52:00.680 --> 00:52:05.440
And it will be all there in the code and it gets all rendered in the documentation.

00:52:05.440 --> 00:52:06.440
That's super cool.

00:52:06.440 --> 00:52:09.280
So two final things I want to talk about.

00:52:09.280 --> 00:52:16.360
One, I was going through the documentation and I saw that there were some optional dependencies, which is pretty interesting.

00:52:16.360 --> 00:52:16.940
Yeah.

00:52:16.940 --> 00:52:22.520
And so, for example, it says some are used by Pydantic, some are used by Starlet, some are used more directly.

00:52:22.520 --> 00:52:30.200
But for example, I could optionally use micro JSON, U-J-S-O-N, but the mu, right?

00:52:30.200 --> 00:52:34.480
The Greek micro, which is a faster implementation of JSON parsing.

00:52:34.480 --> 00:52:39.560
And I guess if I just do pip install FastAPI, it just installs what it requires.

00:52:39.560 --> 00:52:43.640
But maybe it uses just the built-in JSON parser, right?

00:52:43.640 --> 00:52:44.400
Yeah, exactly.

00:52:44.400 --> 00:52:53.600
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.

00:52:53.760 --> 00:52:59.780
But if you need to have like the maximum performance, you can also install U-J-S-O-N and the TelFastAPI.

00:52:59.780 --> 00:53:06.860
Like, hey, I want you to use not the standard JSON responses.

00:53:06.860 --> 00:53:09.900
This U-J-S-O-N library to serialize all the data.

00:53:10.120 --> 00:53:15.420
And actually, there in the documentation, I think in the main point where I say like, these are the optional dependencies.

00:53:15.420 --> 00:53:17.880
There's only U-J-S-O-N is the only one mentioned.

00:53:17.880 --> 00:53:24.800
But you can also use OR-J-S-O-N, which is equivalent to U-J-S-O-N, but is written in Rust.

00:53:24.940 --> 00:53:33.320
And in some benchmarks is faster than U-J-S-O-N, you actually get like different ways to optimize whatever you want to do.

00:53:33.320 --> 00:53:40.380
And to optimize like independently for each one of the things and each one of the endpoints that you need to have.

00:53:40.380 --> 00:53:41.020
Interesting.

00:53:41.020 --> 00:53:41.360
Yeah.

00:53:41.360 --> 00:53:50.140
And you also, Starlette has an optional aiofiles dependency, which will give you async and await capabilities for working with files.

00:53:50.140 --> 00:53:54.500
And that plugs into like file response and static file responses and stuff like that.

00:53:54.620 --> 00:53:55.180
Yeah, exactly.

00:53:55.180 --> 00:53:59.660
So it's actually that Starlette is really, really lean.

00:53:59.660 --> 00:54:03.480
Like the main code is very small and it's actually beautiful.

00:54:03.480 --> 00:54:06.160
It's really enjoyable to read.

00:54:06.160 --> 00:54:11.360
And it just plugs into different components and different parts for different things.

00:54:11.360 --> 00:54:17.400
So when you use Starlette alone or FastAPI alone, for example, it won't include any ORM.

00:54:17.400 --> 00:54:23.220
It won't include Jinja by default because you don't necessarily have to use templates.

00:54:23.620 --> 00:54:28.180
But if you need templates, then you just import Jinja and use the templates functionality internally.

00:54:28.180 --> 00:54:35.020
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.

00:54:35.480 --> 00:54:43.420
That also allows you to have like very minimal applications that are not bloated with different packages and dependencies and things.

00:54:43.420 --> 00:54:43.780
Right.

00:54:43.780 --> 00:54:49.480
But at the same time, you can grow very large to solve the use cases that you need to deal with.

00:54:49.480 --> 00:54:50.080
Yeah, that's cool.

00:54:50.080 --> 00:54:53.220
It's like a micro framework philosophy adopted there.

00:54:53.320 --> 00:54:54.320
Yeah, exactly.

00:54:54.320 --> 00:54:54.720
Exactly.

00:54:54.720 --> 00:54:54.800
Exactly.

00:54:54.800 --> 00:54:56.540
Last one is about hosting.

00:54:56.540 --> 00:55:07.240
So I saw that it ships with uvicorn, which is like the ASGI Python server equivalent of Gunicorn, but based on uvloop.

00:55:07.240 --> 00:55:07.740
Is that right?

00:55:07.740 --> 00:55:08.440
Exactly.

00:55:08.440 --> 00:55:09.900
That's exactly correct.

00:55:09.900 --> 00:55:11.100
So uvicorn.

00:55:11.100 --> 00:55:17.100
And uvloop is a high performance async and await, like event loop, basically written in C or something like that.

00:55:17.180 --> 00:55:23.300
Yeah, and uvloop is the thing that has been providing all this high performance for all these high performance frameworks.

00:55:23.300 --> 00:55:35.220
Like starting with Sanic, the main idea they had was let's run everything using this additional optional loop that is going to do all the asynchronous stuff.

00:55:35.220 --> 00:55:37.540
And that's what provides all the huge performance.

00:55:37.540 --> 00:55:45.220
So Starlette and FastAPI are frameworks, which is one of the sides of like the whole process.

00:55:45.520 --> 00:55:53.320
Like when we were talking about this specification, this ASGI or ASGI specification, on one side you have the framework and on the other side you have the server.

00:55:53.320 --> 00:55:55.900
uvicorn will stand on the server side.

00:55:55.900 --> 00:56:05.420
You can use uvicorn, but you can also use another one called Hypercorn, or you can use the one that is created by the same guys from Django, which is called Daphne.

00:56:06.060 --> 00:56:14.220
And you can use, for example, you can have uvicorn, which like starts a process using this uvloop server.

00:56:14.220 --> 00:56:24.200
But you can also have Unicorn, the standard you will use for Flask, running a worker of uvicorn, like and running several workers.

00:56:24.200 --> 00:56:35.440
So you can have several processes that all have like this massive high concurrency serving your application, all handled by the same unicorn as you will normally do.

00:56:35.440 --> 00:56:38.220
Which is probably what you want to do in a production, right?

00:56:38.220 --> 00:56:49.580
You very often have five or 10 worker processes that are controlled by GUnicorn or Microwisgee, and then they clone themselves for the, to get the parallelism that you really would expect.

00:56:49.580 --> 00:56:54.280
Yeah, exactly. And that's precisely what I do with the official Docker image for FastAPI.

00:56:54.280 --> 00:57:08.020
It just does that. It has Unicorn, it runs uvicorn, and then it runs your application, and it spawns the amount of processes depending on the amount of processes available to the node that is running that Docker container.

00:57:08.020 --> 00:57:16.460
So you can just like create the Docker file, the basic Docker file, copy your app, and it just like, by default, is fine-tuned to work pretty well.

00:57:16.460 --> 00:57:16.740
Yeah.

00:57:16.740 --> 00:57:17.680
If you use Docker.

00:57:17.820 --> 00:57:21.240
So yeah, like that will probably be like the main combination you will have.

00:57:21.240 --> 00:57:23.220
Unicorn with UbiCorn running your application.

00:57:23.220 --> 00:57:35.980
Cool. What if I do it wrong and I host it under straight GUnicorn or I host it under Microwisgee, both of which I don't think support ASGI, not to my knowledge anyway.

00:57:35.980 --> 00:57:41.560
What if I host it in something that is just a WSGI server, not a ASGI server? What happens?

00:57:41.560 --> 00:57:43.380
It just won't work.

00:57:43.380 --> 00:57:44.740
It doesn't work at all? Okay.

00:57:44.960 --> 00:57:52.980
It probably just won'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 WSGI.

00:57:52.980 --> 00:58:02.560
But actually most of the servers nowadays support ASGI. So you can actually use these frameworks very easily with most of these software as a service platforms.

00:58:02.560 --> 00:58:17.260
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 FastAPI applications and run them as, what is the name?

00:58:17.260 --> 00:58:21.280
These function services like Lambdas, these serverless things.

00:58:21.280 --> 00:58:22.180
Right, right, right.

00:58:22.180 --> 00:58:31.040
So you don't have to have a server running all the time. You can also like use these same tools, same ideas and run them in one of these function providers.

00:58:31.040 --> 00:58:37.940
Oh, that's interesting. Yeah. Yeah, yeah. Cool. All right. Well, very cool project. Thanks for doing a deep dive into it.

00:58:37.940 --> 00:58:45.500
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.

00:58:45.500 --> 00:58:48.480
Thank you very much for the invitation. It's been really great.

00:58:48.480 --> 00:58:52.660
Yeah, absolutely. Now, before we get out of here, though, I got to ask you the final two questions.

00:58:52.660 --> 00:58:53.520
Sure.

00:58:53.820 --> 00:58:58.640
If you're going to work on FastAPI, what editor do you use these days?

00:58:58.640 --> 00:59:06.160
So I'm currently using Visual Studio Code, and they recently launched the new plugin for Python, which is called PyLens.

00:59:06.160 --> 00:59:11.180
And it's really, really good. Yeah, that's my main editor currently.

00:59:11.460 --> 00:59:27.360
Nice. And PyLens is a new language. Basically, it's the new Python plugin or built atop 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.

00:59:27.360 --> 00:59:30.700
So it's kind of levels up the autocomplete and the tooltips and whatnot.

00:59:30.700 --> 00:59:37.300
Exactly, because I was a complete and some of these things were pretty good with the previous plugin in Visual Studio Code.

00:59:37.720 --> 00:59:41.640
But this one uses another tool. It's actually all written in TypeScript.

00:59:41.640 --> 00:59:48.280
But the thing is that it provides very good autocompletion type checks, and it has like a detection of dead code.

00:59:48.280 --> 00:59:58.360
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.

00:59:58.360 --> 01:00:03.140
It also has a support, like it detects types very, very well.

01:00:03.260 --> 01:00:14.000
There are some advanced ways that you can declare type annotations and that many or at least the previous version of this editor and some other editors were not able to catch it very well.

01:00:14.000 --> 01:00:23.220
For example, when you use path leave paths, the new plugin get them very well, even when you do like sophisticated operations, including strings and things like that.

01:00:23.220 --> 01:00:24.920
So it actually works pretty, pretty well.

01:00:24.920 --> 01:00:25.660
Very cool.

01:00:25.660 --> 01:00:27.140
Yeah. And I said that's quite new.

01:00:27.140 --> 01:00:29.660
And then notable PyPI package.

01:00:29.660 --> 01:00:31.740
Obviously, there's pip install FastAPI.

01:00:31.740 --> 01:00:36.020
But, you know, some package you've come across lately that you're like, oh, you should definitely know about this.

01:00:36.020 --> 01:00:49.580
So I sort, which is actually a command line package is one of the packages to do linting and recently got a new release that I sort is for doing automatic sorting of the imports in a file.

01:00:49.580 --> 01:00:49.940
Yeah.

01:00:50.080 --> 01:00:58.120
So you're going to, I can be very sloppy in my code and just import anywhere I'm writing the code right on top of the function.

01:00:58.120 --> 01:01:01.860
I just import it and then I make it sort all the imports.

01:01:01.860 --> 01:01:05.460
So it's very nice and keeps the code very tidy.

01:01:05.460 --> 01:01:08.400
So that combined with black and other tools, it's great.

01:01:08.400 --> 01:01:12.360
But I think iSort deserves a lot more attention than it's getting right now.

01:01:12.360 --> 01:01:13.060
Very cool.

01:01:13.060 --> 01:01:14.020
Yeah, that's a nice one.

01:01:14.020 --> 01:01:14.520
All right.

01:01:14.520 --> 01:01:15.240
Final call to action.

01:01:15.240 --> 01:01:17.280
People are interested in FastAPI.

01:01:17.280 --> 01:01:18.260
They want to get started.

01:01:18.940 --> 01:01:23.980
You know, how can they bring this into their maybe existing API apps or create new APIs with it?

01:01:23.980 --> 01:01:24.480
What do you tell them?

01:01:24.480 --> 01:01:30.000
So I think the first thing is that I guess many people are like, hey, this seems kind of cool.

01:01:30.000 --> 01:01:38.940
I'm not sure if I'm into it, but maybe the first thing will be just to read the main page of the documentation and try the examples there.

01:01:38.940 --> 01:01:42.140
It's like, I don't know, it will take about 10, 15 minutes or something.

01:01:42.140 --> 01:01:44.540
And that's enough to know if you like it or not.

01:01:44.540 --> 01:01:45.560
That will be the main thing.

01:01:45.680 --> 01:01:49.440
Like just the main page is enough to know if you like the thing or not.

01:01:49.440 --> 01:01:52.320
If you don't like it then you won't like it later.

01:01:52.320 --> 01:02:06.080
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.

01:02:06.280 --> 01:02:08.400
I have to tear it all down and rebuild it with this.

01:02:08.400 --> 01:02:08.800
Absolutely.

01:02:08.800 --> 01:02:09.200
Yeah.

01:02:09.200 --> 01:02:09.440
Yeah.

01:02:09.440 --> 01:02:09.680
Yeah.

01:02:09.680 --> 01:02:10.040
Yeah.

01:02:10.040 --> 01:02:12.680
We rebuilt it from scratch.

01:02:12.680 --> 01:02:13.420
Yeah.

01:02:13.420 --> 01:02:20.040
And it's normally not a very good idea because you have some tool that is already tested and it is already working.

01:02:20.280 --> 01:02:28.740
And if this new thing is not really providing a very huge benefit to the thing that is already there working, it's probably not the best idea.

01:02:29.000 --> 01:02:42.140
What many teams do and what I actually have done in many occasions is to add a layer of FastAPI on top of the current application, be it like, I don't know, Django REST framework, Flask or whatever.

01:02:42.140 --> 01:02:45.820
And then add the new features in this FastAPI application.

01:02:45.820 --> 01:02:51.200
And whenever I have to refactor something from the old application, then I just move it to FastAPI.

01:02:51.200 --> 01:02:52.840
So and then I just refactor it.

01:02:52.840 --> 01:03:02.000
But the thing is that FastAPI doesn't have like any compromise with database, with the specific tools that you use for security or for session management or for anything.

01:03:02.000 --> 01:03:09.360
It's actually compatible with all the other tools and it's compatible with the database that you're already having and with the applications that you're already having.

01:03:09.440 --> 01:03:16.040
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.

01:03:16.040 --> 01:03:23.260
So everything that goes to API slash version one goes to Flask and API slash version two goes to the new FastAPI application.

01:03:23.260 --> 01:03:28.140
I think that's a very good strategy that should work for many people when they want to add stuff.

01:03:28.140 --> 01:03:31.540
Cool. And the mechanics of that might be in Nginx.

01:03:31.740 --> 01:03:41.880
Instead of just saying pass everything to this URL, you can say pass everything to slash V1 slash to here, to this port or this socket and then the other one over there and kind of behind the scenes.

01:03:41.880 --> 01:03:43.220
But at the front end, nobody knows.

01:03:43.220 --> 01:03:44.060
Yeah, exactly.

01:03:44.060 --> 01:03:46.020
You will do that with Nginx or Traffic.

01:03:46.020 --> 01:03:48.580
I really like Traffic and I use it for a bunch of things.

01:03:48.580 --> 01:03:54.840
It's also like has like automatic support for HTTPS certificates with Let's Encrypt.

01:03:54.940 --> 01:03:58.460
And it just keeps them, makes sure that it's renewing them.

01:03:58.460 --> 01:04:00.780
So like it's a very nice system.

01:04:00.780 --> 01:04:06.320
And you can very easily say like, yeah, everything that goes to that specific path goes to one side and it'll be all the other.

01:04:06.320 --> 01:04:08.520
Nginx, there's also like HAProxy.

01:04:08.520 --> 01:04:11.300
And there's a bunch of others that can do the job.

01:04:11.300 --> 01:04:14.040
And it's actually not that difficult to set up.

01:04:14.040 --> 01:04:18.840
And it will probably save you like a lot of headaches with deadlines that are not fulfilled.

01:04:18.840 --> 01:04:19.280
Right.

01:04:19.280 --> 01:04:20.880
And if you don't like it, you just switch it back.

01:04:20.880 --> 01:04:21.800
Yeah, exactly.

01:04:21.800 --> 01:04:22.380
Exactly.

01:04:22.380 --> 01:04:22.900
Yeah.

01:04:22.900 --> 01:04:23.260
Cool.

01:04:23.260 --> 01:04:28.080
Nevertheless, I have seen a bunch of teams that have been migrating the whole thing to FastAPI.

01:04:28.080 --> 01:04:30.800
Unfortunately, they have been happy about it.

01:04:30.800 --> 01:04:33.780
But yeah, I wouldn't suggest that as the main approach.

01:04:33.780 --> 01:04:34.240
Sure.

01:04:34.240 --> 01:04:34.660
Cool.

01:04:34.660 --> 01:04:37.160
I guess it depends on the size of the project as well.

01:04:37.160 --> 01:04:37.960
Yeah, of course.

01:04:37.960 --> 01:04:38.380
Of course.

01:04:38.380 --> 01:04:39.320
Yeah, for sure.

01:04:39.320 --> 01:04:43.440
This has been another episode of Talk Python To Me.

01:04:43.440 --> 01:04:45.860
Our guest on this episode was Sebastian Ramirez.

01:04:45.860 --> 01:04:48.940
And it's been brought to you by Linode and Talk Python Training.

01:04:48.940 --> 01:04:53.760
Start your next Python project on Linode's state-of-the-art cloud service.

01:04:53.760 --> 01:04:58.080
Just visit talkpython.fm/Linode, L-I-N-O-D-E.

01:04:58.080 --> 01:05:01.380
You'll automatically get a $20 credit when you create a new account.

01:05:01.380 --> 01:05:03.520
Want to level up your Python?

01:05:03.520 --> 01:05:08.380
If you're just getting started, try my Python Jumpstart by Building 10 Apps course.

01:05:08.380 --> 01:05:12.680
Or if you're looking for something more advanced, check out our new Async course.

01:05:12.840 --> 01:05:16.520
That digs into all the different types of async programming you can do in Python.

01:05:16.520 --> 01:05:20.480
And of course, if you're interested in more than one of these, be sure to check out our

01:05:20.480 --> 01:05:21.200
Everything Bundle.

01:05:21.200 --> 01:05:23.080
It's like a subscription that never expires.

01:05:23.080 --> 01:05:25.220
Be sure to subscribe to the show.

01:05:25.220 --> 01:05:27.640
Open your favorite podcatcher and search for Python.

01:05:27.640 --> 01:05:28.860
We should be right at the top.

01:05:28.860 --> 01:05:31.820
You can also find the iTunes feed at /itunes.

01:05:32.080 --> 01:05:33.700
The Google Play feed at /play.

01:05:33.700 --> 01:05:37.860
And the direct RSS feed at /rss on talkpython.fm.

01:05:37.860 --> 01:05:39.940
This is your host, Michael Kennedy.

01:05:39.940 --> 01:05:41.440
Thanks so much for listening.

01:05:41.440 --> 01:05:42.480
I really appreciate it.

01:05:42.480 --> 01:05:44.240
Now get out there and write some Python code.

01:05:44.240 --> 01:05:44.860
Thank you.

01:05:44.860 --> 01:05:45.240
Thank you.

01:05:45.240 --> 01:06:04.920
Thank you.

01:06:04.920 --> 01:06:34.900
Thank you.