Modern APIs with FastAPI and Python Transcripts
Chapter: Building a realistic API
Lecture: Partitioning with routers
0:00 Well, we're off to a good start.
0:01 We've got our Jinja templates. We've got our static files.
0:04 We've got our homepage. We're gonna add,
0:06 of course, a few more things.
0:07 But before we get too involved,
0:09 I want to add a little more structure,
0:11 a little more organization, to what we're building here. Now,
0:14 to be fair, this API, this app, is not really complicated enough to
0:18 super justify this, but I would do it anyway
0:21 and certainly as your API and your apps grow, you would really,
0:24 really appreciate some organization. So let's go ahead and put a few more pieces in
0:29 here. We're gonna do "api.get".
0:32 Now remember I showed you that If we ask for a favicon
0:35 it got a 404? I don't think we need request here.
0:41 And all we gotta do is just do a redirect.
0:43 So we're gonna return FastAPI.
0:46 Whoops, this should be "favicon
0:48 ico" somebody ask for that.
0:50 We're gonna do "responses, redirect response".
0:53 And where is it we want them to go?
0:54 The URL is going to be "static/
1:01 OK, so these are kind of related with the homepage, have to
1:04 do with that. And then we're gonna have an API,
1:07 let's just put weather for now, and then we're gonna have this,
1:10 let's call it "weather" and let's just say it's gonna return some report for the moment.
1:14 It doesn't really matter what we're returning.
1:16 But as you can see, these are gonna get more complicated,
1:19 especially this one. We're gonna have more API methods,
1:22 and it's gonna just turn this sort of app startup file into a complete mess.
1:27 So what do we do?
1:28 Well, no problem. There's plenty of organization that we can do.
1:32 So let's go over and make a directory called "api"
1:34 and let's make one called "views". All the API implementations
1:38 are gonna go in the API
1:39 one and the stuff that does templates basically is going to go in the views. Over
1:44 here, let's make a file called "home".
1:46 Maybe we have stuff in like account management, one for I don't know,
1:50 browsing weather locations and so on.
1:53 But we're gonna have stuff to do with home
1:54 go over here. We can just go and nab these things and drop them there.
1:59 It's not gonna work yet, but it's sort of the path.
2:01 And then over here, I'll add weather
2:05 API. Go back, we're gonna take this one.
2:08 Gonna put those there. Now, what happens if I run this?
2:12 Well, Surprise, it survived. Okay,
2:13 That's cool. How about now?
2:15 Does it work well? No.
2:17 404. What happened?
2:18 Well, the problem is how does this app know about those other things,
2:24 right? We didn't import them.
2:26 We haven't done anything. So maybe we could do this "from api
2:30 import weather_api and from a views import home".
2:35 Maybe that'll make it better. Yeah,
2:36 that's not better. That's definitely not better.
2:38 So we end up with this chicken and egg problem.
2:41 We need to create one of these here and then over here,
2:44 we need to use it. But in order to find the weather stuff we've gotta
2:48 import it here, the way we would get it over
2:50 there is we would import main.
2:51 We'd import weather, import main, import weather,
2:53 that's a circular reference. Some languages deal with that, Python doesn't.
2:57 So that's not how we want to organize these things.
3:00 So instead, we're going to use another concept called "API routers", put that back.
3:04 So we'll go over here and say "import fastapi"
3:08 we'll say a "router = fastapi.APIRouter()" like that.
3:15 What is the goal of this?
3:16 Well, whatever you would have done with the app or API itself, now we can do
3:19 get, post, and so on. And then we add this router in to what we're
3:27 doing with the main app. So let's do that with the home is well while
3:30 we're here. And we also have this template thing we had going on here,
3:41 which only actually makes sense in this place.
3:43 So let's go and add that as well.
3:47 I'm gonna need to import requests from starlette, a little bit of organization,
3:52 but no more errors there. No more errors here.
3:55 So the last thing we need to do, notice this where we're mounting the routes, I'm
3:59 gonna improve this as well,
4:00 but we need the "api.include_router()"
4:03 Let's do "home.router" and weather,
4:09 Just run it to see that that works.
4:11 Okay, So what we do is we basically define little sub parts of our application
4:15 in these routers, and we just bring them all together here. Run again.
4:19 Wooo! Beautiful, beautiful! If we click this,
4:23 what's going to happen? We get some report.
4:26 Awesome. So our API is working as well as our home page. And,
4:31 get it to refresh, Oh
4:32 yeah, Check it out. We even got it to put the favicon up
4:35 there. Super sweet. So we can use this.
4:39 We can use these routers to have a much,
4:43 much, much better organization of our code instead of cramming it all into the main.py.
4:49 Final thing, let's do a little bit more organization here.
4:54 Let's go and define a method called "configure"
4:58 and here we're going to, I guess we'll have configure, configure routing, and let's have a
5:07 function here. Why? Why would I have just one function that just calls another?
5:11 Because we're gonna be doing other things.
5:12 Configuring the database, configuring API keys,
5:15 configuring this, so this this area will grow.
5:18 And now if I just run it like this,
5:21 we're gonna be back to our 404. Alright,
5:24 404. So what we need to do is we need to make sure
5:28 that we call configure first and this is super tricky
5:31 what's going on here. A lot of times when we run in production,
5:35 this code is not run in this way.
5:37 So this should fix it, get it to come up.
5:40 There we go. So it works again.
5:42 But let's see if I could make it run the way it would in production.
5:46 Come down here. We would say "uvicorn",
5:49 I think it's dash, "-b main:api"
5:53 like this. There we go. uvicorn.
5:56 Let's see what we're supposed to do.
6:03 Maybe it's just like this. There we go.
6:05 Alright, It looks like it worked
6:06 yeah? So should be fine.
6:09 we're back to not found again.
6:10 What's going on? Here's what's going on.
6:13 Check this out. So it just imported this file,
6:16 didn't run the main stuff, and that meant configure didn't get called.
6:19 So we need to have an "else",
6:20 and this is what happens in production is down here.
6:23 I'm gonna do this little configure thing.
6:25 Now I go down to the terminal and I uvicorn it. It's back to working, okay.
6:33 And again, if I run it like this, also working. Awesome.
6:38 So we've got some organization done here.
6:40 We've got the structure of our main.py to help organize the startup code and
6:46 like things like database connections,
6:48 all that kind of stuff that we're gonna have to sort of pile on here,
6:51 right? Not quite there yet,
6:52 but we're getting there. And then,
6:53 more importantly, we've put all the home stuff over here into the views.
6:59 And we put the API pieces into their own files as well.
7:03 This one thing that we could also do is we could do
7:06 like this. Come over and say there's going to be all the views that have to
7:10 do with home go in there. And we have a shared, that could go in there,
7:18 because as we have more views,
7:19 you probably wanna have some structure as well.
7:21 And that means, oh look at that. PyCharm
7:23 re-factored it. That is fantastic.
7:25 Did it do it over here?
7:26 No, no, no, no,
7:27 man, if it did, that would have been awesome.
7:29 Say home slash to include the directory.
7:31 Let's see how this works. Yeah,
7:34 it does. Layout is there. You can see you know that the layout got imported because
7:38 of the CSS is still here.
7:40 Yeah. Perfect. Okay, so now we've got some organization around our templates, around
7:45 our API's, around our views, and our main app, our main.py,
7:50 our main app start up.