Modern APIs with FastAPI and Python Transcripts
Chapter: Accepting inbound data
Lecture: Weather report data layer
0:00 Let's begin our work on this writable data,
0:03 this ability to accept data from users by creating the data access layer,
0:07 not the API layer,
0:08 but the part that the API layer will use to read and write data.
0:11 So fire up a PyCharm. Now I've gone and already copied what we did in the
0:15 previous chapter, chapter six error handling, over into chapter seven, moment,
0:20 for inbound data. So it's just picking up exactly where we left off,
0:24 and we're gonna work over here by adding some other functions,
0:28 not "give us the weather" but "here's a report" and "what are the reports out
0:32 there currently"? So in our services we've already got one service here for interacting with the
0:38 external API. I'm gonna add another one for interacting with the data around
0:42 reports. Call it "report_service". This is not Web service
0:48 in that sense, this is just,
0:49 like provides a service to the app,
0:51 okay? Over here, we're gonna have two functions: def
0:55 get reports, and this one takes no arguments.
0:58 It's just going to give us all the reports or maybe the last 10 recent ones
1:01 or something like that, and it's going to return
1:03 a list of something. What goes there?
1:07 I'm gonna have to create a class or something that goes there.
1:10 But for now, let's just return nothing.
1:12 And then let's also defined on add report.
1:16 This is gonna take a description,
1:19 it's a string. Remember, we already have over in our models,
1:22 we have a location. We're gonna let, you know we need to have a location
1:26 for that particular report, right?
1:29 It was in Portland, or it was in New York City or whatever.
1:32 So we're gonna pass that over,
1:34 which means we gotta import that,
1:35 and then it's gonna return something,
1:38 Something up here. We're gonna say it returns something for the minute like this.
1:42 But what we need to do is we're gonna define the class. The same thing we
1:45 return there is the same thing that's going to be contained in these lists.
1:49 Now we're going to need a database to store this in.
1:52 Just like I said about the caching,
1:54 we could set up interesting infrastructure.
1:55 We could use mongoDB,
1:57 or we could use postgres,
1:58 or we could use some other system to store this, or who knows a file system,
2:01 Some random thing. But because I want to keep this super, super simple for
2:06 you, I'm just gonna have a empty list here.
2:09 Now, we can just do return
2:11 a list of the reports.
2:13 Why not just return the reports itself?
2:15 We don't want them to modify it,
2:16 so we're going to return a copy of it.
2:19 I guess we could just do reports.copy
2:21 but this will have the same effect.
2:22 But here's the thing, If we go to one of these and we say "dot"
2:26 what's in there? We don't know.
2:28 So it's gonna be good for us to define a class that holds that.
2:32 And it makes sense for us to define this at different levels because it's gonna be
2:37 easy for us to reuse some of it over here. Now,
2:39 in practice, I'm not sure that would really happen.
2:41 In practice, we might have database models and then pydantic models on the edges.
2:45 But for this case, let's just go over here and create a file called
2:50 "reports". And what we'll do is we'll have a class called a "report".
2:56 We'll start out in one way that's not where we're gonna end up,
2:58 but we'll have a base model.
3:01 And what is the report gonna have?
3:02 It's gonna have a description, which is a string,
3:06 and it's gonna have a location.
3:07 Now, this is super cool what we could do with pydantic here. Location,
3:10 which is a location of that variety.
3:15 So what we can do is we can say our report actually has
3:18 this description and a location and we also wanna have a created date, which is
3:23 an optional datetime. I've got to import a few things to make all that work. Dot datetime.
3:29 So this was "when was it created"?
3:33 Perfect. This is the object that we're going to exchange. We're able to use our
3:37 location already. We're here in the report services.
3:40 What this is going to do is going to return a list of report. This,
3:44 we still don't know what goes on here,
3:47 right? We still don't get any help.
3:48 But if we go up and say "this is a list of report as well"
3:52 all of a sudden PyCharm and
3:54 everything else knows it has a location and locations have countries and so on,
3:58 right? So this is really a good idea.
4:00 Put the type there, and then this is now going to return a report. So
4:05 when we go and pass this data over,
4:07 it's going to create this object and then send it back as well as store it into
4:11 our reports list. So let's go over here and just capture what
4:15 datetime dot now is, like that.
4:20 And we gotta import that here as Well.
4:23 Then we're gonna create a report,
4:24 which is a report of this type.
4:27 And notice, it takes stuff here, some arbitrary data,
4:31 and the data it takes is "location equals location,
4:36 description equals description, and created date equals
4:41 now". And then we're gonna return the report,
4:44 but we also wanna save it.
4:46 Now, this is where we're simulating saving it the database
4:50 because we're just having this simple thing like that.
4:55 Alright, so we're gonna create one of these,
4:57 put it into the report, saving location,
4:59 the database type of thing, and then we'll just return it there.
5:04 Alright, let's see if we can actually do a little test on this. Not
5:08 terminal but the console. So let's see if we can make this happen.
5:11 So from services import report service, then we can try report service dot get reports, should be an
5:20 empty list. We're going to add a report.
5:24 What goes in here? We have the tornado and the location.
5:28 We're gonna have to import that.
5:31 Hold on. Alright, let's see what happens if I run this.
5:41 Oh, that's pretty cool. Alright.
5:42 And then we have, this is our item here.
5:46 We've got our created date and everything else,
5:48 so it looks like this is great.
5:49 Let's add one more report. This one is gonna be in Beaverton, a
5:53 city near Portland. This is going to be hail.
5:58 Now if we get the reports, we should have, it wraps
6:03 wraps, wraps, wraps, right. We've got our hail and we've got our description there.
6:08 Another thing that we probably want to do. When we put these in
6:12 and then we ask for them back,
6:13 we probably want to get the most recent ones,
6:15 not the oldest ones. Right now,
6:17 we're getting them in the order they were created.
6:19 We probably want the most recent.
6:20 So let's do, after we do this,
6:23 let's do a sort here. We'll
6:28 say given some kind of report, what we want to do?
6:30 We want to sort by created date, reversed
6:34 true. And now I guess if we, we could re-import this and do the same
6:40 things, but you'll see that it's been reversible. It's getting a little clumsy to play
6:43 with. So we've created this data access layer,
6:46 talking to our fake database.
6:48 One final thing I want to do is I wanna make this feel a little bit
6:51 more real, even though I am faking it with this in-memory database.
6:56 So in a real database,
6:58 we would very likely wanna have an asynchronous database driver or library to talk to it
7:03 like the new version of SQLAlchemy or peewee or some of these different ones.
7:08 We'll make this async, and I'll just put a
7:12 message that says this would be an async call here.
7:14 It's not. We're not actually using the async aspect.
7:20 But like this part right there,
7:23 right, this would be the data call,
7:25 right? This would be insert into the database and this would be query from the
7:28 database. So just to give you a more real feel when we consume this in
7:32 our FastAPI, this is probably what you want to aim for.
7:36 So we built our models and we built our little data access layer.
7:40 we should be able to create an API around this real easy now.