Modern APIs with FastAPI and Python Transcripts
Chapter: Error handling and performance
Lecture: Faster with caching data
0:00 It may feel like we've made a lot of progress with our
0:02 API, and it feels like it's working.
0:04 So ship it. It's done,
0:05 right? Yeah, yeah, no,
0:07 not so much. You'll see
0:08 there's a couple of things we need to work on.
0:10 It really lacks some validation and proper error handling.
0:13 We can do a huge thing for performance.
0:15 And we take these errors that come in and we're not converting them correctly,
0:19 so we're getting a lot of crashes,
0:20 so it's sort of tied to validation,
0:22 I guess. But even when there are crashes,
0:24 we want to do something different than what's happening now.
0:27 So let's jump over here, and I've made a copy of what we built in
0:30 Chapter five and put it into Chapter six.
0:32 So you have an exact copy of the chapter five way,
0:35 and then now what we're doing here. And set it up here in PyCharm,
0:38 ready to go. So this is exactly where we last left off in the other
0:43 chapter, Chapter five. Let's look at a couple things.
0:46 If I go over here and I rerun this,
0:48 get it to open again. Let's go look at our API.
0:51 I'll use some fancy performance tools
0:54 like just this. Let's go and
0:56 make a request. Well, that took 400 milliseconds.
0:59 Do it again. 500 milliseconds.
1:01 400 milliseconds. How much of that time do you think is us?
1:05 And by the way, 400 milliseconds,
1:07 that's like we got a lot more scalability than that 100X I was telling you
1:10 about, as we'll See here in a second.
1:11 It turns out going over to the API and asking for the current weather,
1:15 Well, that takes a lot of work.
1:16 But if we're asking for the same thing like "what's the chance
1:19 the weather just change right now?"
1:21 Maybe refreshing that every 15 minutes would be sufficient.
1:24 Maybe once an hour. So that's the first thing that we're gonna do.
1:27 We're gonna add some caching. I'm gonna add a general little area to organize stuff
1:31 called "infrastructure". And in there we'll put a weather cache.
1:37 Yeah, it's a little bit messy,
1:38 so I'm gonna go ahead and just drop in some code and then talk you through
1:41 it. So over here, what are we gonna do? For this simple version,
1:46 We're just gonna cache in memory, and we're doing that by just having a module level
1:51 global variable, I guess.
1:53 Semi-global if you ask for it.
1:55 Good reason to double underscore is you can't really get to it outside,
1:58 so let's just call it module level.
1:59 And we're gonna say we only want to refresh the cache once an hour,
2:03 so then we're going to say, "give me the weather and see if the cache has
2:06 a new weather". This is exactly the same arguments as we're passing along to our
2:11 open weather map API.
2:12 And if we have some kind of report, so we're gonna get a dictionary back.
2:17 If there's something in the cache and it's not too old,
2:21 otherwise we're gonna get "none", so here you can see we tried to get it back
2:24 If there's no data, none, and we'll try to go and see when the
2:28 last time we put it in the dictionary
2:30 was. Here's a cool little trick you can do,
2:32 take the current elapsed time and divide it by a time Delta,
2:35 which is set to some amount. It will tell you how many of those there are.
2:38 So this little bit of math is not obvious, but that will tell us as a float
2:42 how many hours have passed.
2:45 And if that's less than one hour,
2:47 then we're going to return that data.
2:49 But if it's too old, we're just gonna return nothing.
2:52 And, you know, it might even be worth going over here and saying "cache
2:57 of key" just so we don't hold on to it after it's expired.
3:01 Okay, so this will get us the weather.
3:03 And then to do the reverse,
3:05 we're gonna set it. We're going to actually create a key,
3:07 which is just a tuple of all the values that actually works in a dictionary.
3:11 So city, state, country, units and so on.
3:14 That's gonna be the key. The value will be the time and the forecast.
3:17 Alright, kind of a lot going on here. In a real one,
3:20 I didn't build this from scratch, because in a real server you would
3:23 probably use like Redis or a database or something.
3:25 But for now, we're just gonna put it memory.
3:27 I really don't want you to have to set up a server and configure that just
3:31 so you can run the demo code.
3:32 So, in memory it is. Now,
3:34 this should be super easy for us to actually use. Could do to the API
3:38 level, right? We could do it here and never even go down.
3:41 But I kind of like that
3:42 this thing is all about accessing the weather and whatnot and keep the view method
3:47 up here simple. So let's tell this thing that it, let's make it responsible for dealing
3:51 with a cache. So we'll say this, we'll say weather equal, or call it forecast, weather
3:58 cache, import that. And then, come down here and just say,
4:02 get weather, city, state, country, units.
4:06 Is that what it wants? City,
4:07 State, country, units. Yes.
4:09 Say, "if forecast return forecast".
4:13 So if we try to go and get it,
4:14 and we could even do one of these things here with the walrus operator.
4:20 Make it in line there. So we're gonna come along and
4:22 say "try to get the forecast".
4:25 If we already had something that was valid,
4:27 it was in the cache, just give it back.
4:29 Otherwise, we're gonna go to the service and create it.
4:31 And before we send it back,
4:33 we need to go weather cache,
4:34 set weather, all of this forecast.
4:40 I think that's the way it works.
4:41 The value is the forecast. That way the next time we call it,
4:45 it'll come out here. So let's try this again.
4:46 re-run it. And the first time,
4:49 it should be just similar times,
4:51 you know, 300-600 milliseconds.
4:53 Whatever. 700, 478. What about the second time?
4:58 2, 1 1 1 1 1 1 1 2 1 2 1. Look at that. It is now 4,
5:05 500 times faster. That is killer.
5:08 Now, if we change it,
5:09 if we want this in metric,
5:11 obviously we can't have that same cache results because these are different things.
5:14 So the next time now it's slow.
5:17 But then the 2nd and 3rd and 4th time.
5:19 And maybe we want this for Tennessee. Again,
5:22 we've got to go back to the API once,
5:24 but now it's cached and super, super fast.
5:27 Cool, right? So again,
5:28 I would probably put that in the database
5:30 or I'd put that in Redis or somewhere, rather than sticking it in memory.
5:34 But you know, honestly, maybe memory is the right place.
5:36 The thing to be keep in mind is, we'll talk about this in the deployment section,
5:39 is when we run this in production, there will probably be
5:42 2, 4, 8, 10 copies of this thing running on different processes on the server.
5:48 So this, this won't capture everything.
5:51 That's why something external, like Redis or a database would be useful.
5:54 But this is already a really big boost, I think.