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