Python FastAPI Tutorial (Part 2): HTML Frontend for Your API - Jinja2 Templates

Corey Schafer · Beginner ·🔧 Backend Engineering ·5mo ago

Key Takeaways

This video tutorial demonstrates how to use Jinja2 templates to create an HTML frontend for a FastAPI application, allowing for dynamic data to be passed to templates and proper HTML pages to be served to users. The tutorial covers setting up Jinja2 templates, passing data to templates, and using template inheritance to reduce code duplication.

Full Transcript

Hey there, how's it going everybody? In this video we're going to be learning how to use templates in FastAPI. Templates allow us to serve up HTML pages to our users while still maintaining our JSON endpoints for the backend API. So we'll set up Jinja2 templates, pass data to templates, use Jinja2 syntax for four loops and conditionals, implement template inheritance with a layout.html, we'll add some bootstrap for styling, and set up static files for our CSS and images. So by the end of this video, we're going to have a good-looking blog homepage that displays our posts in a nicely styled layout. All right, so let's talk about why templates are important. So in the last video, we returned some raw HTML strings with our home route here. And that works fine for something super simple, but once you need full HTML pages with headers, navigation, footers, and styling, then managing all of that in a Python string would be a nightmare. So that's where templates come in. So they let us write proper HTML files and just pass in our dynamic data. Now, on the other hand, our API posts return JSON, which is perfect for API access, but it's not something that most humans want to read directly in the browser. So we need a better solution here. And that solution is going to be using templates. So we're going to keep our API routes returning JSON, and we'll add page routes that return proper HTML using templates. So both can use the same data, but they serve different audiences. So let's do a quick reminder of where we're starting from here. So we're currently within our main.py file, and this is what we created in the last video. And just to make sure that we're all on the same page, let me go ahead and run this app currently so that we can see what we're starting with. So I'm going to open up my terminal here. I'm going to kill the development server that I'm already running. I'm going to rerun that. I'm using UV run FastAPI dev main.py. That's because I'm using UV throughout this series. If you're not using UV and you're just using something like pip, you can just say FastAPI dev main.py. So I'm going to run that server, and now let's go back to our browser and reload our page here. And we can see that for our home route, we have that simple H1 tag with the first post title. And if we go to /api/posts, I'll make this a little larger here, we can see that we get a JSON list of all of our current posts. And we just have those two dummy posts for now. All right, so now let's get started with templates. So the first thing to know is that if you installed FastAPI with FastAPI standard like we did in the last tutorial, then Jinja2 is already included. You don't need to install anything extra. So Jinja2 is the templating engine that FastAPI uses, and it's the same one that Flask uses also. So if you've ever worked with Flask templates, then this is going to look very familiar. Now, if for some reason you didn't install FastAPI with FastAPI standard, then you would need to install Jinja2 separately. You can do that with a pip install Jinja2, or you can do that with a UV add Jinja2. Okay, so let's go back to our application here. So first we need to import what we need from FastAPI. So I'm going to add request to our FastAPI import because Jinja2 templates require the request object, and I'll also import Jinja2 templates from FastAPI.templating. So from FastAPI here, I'm going to add in request, and also I'm going to say from FastAPI.templating, I'm going to import Jinja2 templates. And we can actually remove the HTML response import since we won't be using that anymore now that we're using templates. So I'm going to go ahead and remove that. And now we need to create a templates directory in our project. So this is the convention in FastAPI and in Flask projects. So the folder should be called templates. So over here in my project directory, I'm going to create this new directory, and I'm going to call this templates. Okay, so now that we have that templates directory, I'm going to close the sidebar for now. And now we need to tell FastAPI where to find our templates. So right after we create our app right here, I'm going to say templates is equal to, and we're going to use that Jinja2 templates that we imported. And I'm going to say that the directory is equal to templates, and that's the name of the directory that we just now created. So this creates a templates object that knows to look in our templates directory for template files. Okay, so now let's create our first template. So inside of the templates folder, I'm going to create a new file here, and I'm going to call this home.html. And now I just want a basic HTML structure here. I have a snippets file so that you don't have to see me type all of this out. This is just a very simple HTML structure here where we have our title, an H1 tag that says homepage, and then just a paragraph tag that says that we are using a template. So it's nothing special yet, but we'll see how we can add to this later. So now let's update our home route to use this template instead of returning that raw HTML string like we were doing before. So now let's change this to use a template response. So first let's remove this HTML response that we have here since we are no longer using that import. So I will get rid of those. Now one thing that we need to add to our actual route function here is a request parameter as an argument here because Jinja2 requires that. So within here, I'm going to accept this request, and I'm going to pass that in as request. Okay, and now instead of returning this HTML string here, we are going to return templates.template_response. And then we are going to pass in that request, and then the name of our template. For now, that is just home.html. So real quick, let me just explain again what's going on here. We removed that HTML response response class since we don't need that anymore. We added our request as a parameter here, which Jinja2 needs to work properly. And then we return templates.template_response with our request and the name of our template file. And we still have include_in_schema equal to false here on both of those routes, which we learned in the last tutorial. This keeps these pages these page routes out of our API documentation at that /docs location. Okay, so now let me save this and test it in the browser. Let me make sure that our server's still running, and it is. So now if I reload the browser here, now we can see that it's returning our HTML template. But right now our template is pretty static. It doesn't actually show our post. So let's fix that by passing data to our template. So in the template response, we can pass a context dictionary as the third argument here. So we have our request as the first one, template name is the second, and then the third, we can pass in a context dictionary. And this dictionary is going to contain all of the variables that we want to be able to use in our template. So for this, it's going to be a dictionary, and one variable that I want to use is going to be called posts, and we'll just pass in all of our posts as the value for that variable. So now I'm passing in our post list to this template, and the template can access anything that's in this context dictionary. So now let's update our template to actually display the post. This is where Jinja2's templating syntax comes in. So to loop through items, we use this curly brace percent syntax. And to display variables, we do a double curly brace syntax. Let me show you this real quick. So right here, I'm going to replace our paragraph, and I'm going to do this curly brace percent sign, and this we can use a for loop. So I'll say for post in posts. And now we need to end this for loop. So I'll do the same thing, curly brace percent sign, and then I can say end for on that. Okay, and now within this, we can use a double curly brace to access some attributes. So I'll just create an H2 tag here, and I'll use these double curly braces here. And we have that post variable since we are looping over those posts. So now I can just say post.title. And then for the body, sorry, my HTML is auto-formatting here whenever I save, so I'll try not to save until I'm done here. So now for the body, I'll use just a paragraph tag. And again, we are going to uh use this double curly brace and we'll just say post.content within those paragraph tags. So, this curly brace percent syntax here for loop loops over our post. We pass these posts in as the context right here. And then within this for loop, we are using these double curly braces and we can access uh those values from that dictionary. Now, something that might look a little strange if you're new to templates is this dot notation here. Uh we're using a post.title and post.content even though post is actually a dictionary. Uh Jinja 2 lets us access uh dictionary keys using dot notation, which is just a more clean way to do it within our templates. So, let me go ahead and save that and now let's go back to our browser and refresh this. And now we can see that both of our posts are displayed on the page. So, each post shows its title and then we have a paragraph tag here with the content. So, now we're dynamically rendering our data now. And now let me show you conditional statements in Jinja 2. So, these are useful for things like displaying different content based on whether a value exists. So, a common use case uh is setting the page title, for example. So, let's update our page title here in the template to show a specific title if one is passed in or a default one if one is not passed in. So, here where we have title, I'm just going to uh cut out that FastAPI blog. And now I'm going to use this syntax again here. So, curly brace uh percent sign and then this is going to be an if conditional. So, I'll say if title and then we will end this if here. So, here I will say end if. And now within this conditional, we can paste in that if we have a title, then we want this to be FastAPI blog. Then we'll just do a dash double curly brace and then display that title after that. Now, I actually uh want an else statement here as well because I also want a default value. So, if we say else right here, now we can pass in a default value. And I'll just have FastAPI blog be that default value there. So, now if we pass in a title into the context of the template, then it will show FastAPI dash with the title. If we don't, then it'll just default to FastAPI blog. So, now let me go update our uh main.py file here and let's pass in a title here to our context. So, I'll just put in a comma there and we will say title and pass in something like home since this is the home route. And let me go ahead and put a comma here so that it uh displays a little bit better. Okay. So, now if I save that, our server should still be running and updating. So, now if I reload the page here, this might be a little difficult for you to see, but up here in my browser tab, it says FastAPI blog dash home. Uh so, that is working correctly. So, that's pretty much the basics of Jinja 2 templating. We have for loops for iterating, uh double curly braces for displaying values, and if statements for conditionals. So, these are the building blocks that you're going to use constantly in your templates. So, now let's talk about template inheritance. So, this is a really powerful feature that will save you a lot of code duplication. So, right now if we wanted to create more pages like um an about page, a single post page, then we would have to copy this entire HTML structure to each template. So, we'd have to copy this head section, um any of our navigation, our footers, all of that would be duplicated. If we did that and then wanted to change a navigation link, then we would have to update that on every single template and that just wouldn't be maintainable. So, template inheritance solves this by letting us create a parent template with the common structure and then the child templates just fill in the parts that are different. So, let me create a layout.html template here in my templates folder. So, I'll call this layout.html. And now I want to use this as our parent template. So, I'll start by taking the structure from our home.html since it has uh pretty much everything in there and I'll modify it here to be a parent template within the layout. So, if we look at this template here, um all of this stuff here is going to be the same on every page. We're just going to have our head with the title, things like that. Now, the body, this is what's going to be different per page. So, I am going to uh get rid of our body here. And now we can create something called a block. So, I'm going to create a block here and again it's just this curly brace percent sign uh syntax. So, I'll say block, I'll call this content. And now underneath this, we are going to use the same syntax here again and I will say end block content. So, what this does is it defines a section called content that the child templates can override. Uh you can have multiple blocks with different names if you need to. So, you could have like a sidebar block or a scripts block. Uh but for now we just have our one content block. So, now let me update home.html to extend this layout instead of having its own full HTML structure. So, within home.html, we're going to use this layout.html and it's going to reuse all of this and then all we are going to do is fill in this content block. So, within here, all we want to do is keep what's here in the body. And actually I'll get rid of this H1 tag as well and we'll just keep our post. So, I'm going to get rid of that H1 tag. And now I'm going to get rid of all this other stuff, too, because all of that is in our layout. So, I'll get rid of all of that. And now let's extend that layout.html. So, I'll use the same syntax that we've been using and I can just say that this extends layout.html. And now we have to tell that layout template uh what section we are overriding. So, we are going to set the content block. So, I'll say block content. Now, I also want to show where this uh block ends. So, down here I will set another one and I will say end block content. And now we just have that for loop inside of that content block. So, now HTML uh home.html is much simpler. Now it just extends that layout.html and just define defines what goes in that content block. Uh the full HTML structure, the head section with the conditional title, all of that comes from the layout. So, if I save this, if I go back to our browser, if I run this, uh we can see that that still works. I got rid of the uh H1 tag, so that's why it looked like something changed there. But if I actually go to view the page source here, uh then we can see that we have the full HTML structure. So, that's working well. So, now if we wanted to create another page, then we to do. And if we wanted to add navigation or change something in the overall structure, then all we need to do is update this layout.html uh file once and it affects all of the pages that inherit from it. All right, so we basically learned the basics, uh but our page still you how to add some styling. So, I'm going to use Bootstrap since I think that is very simple for most people to use and understand, but you could use Tailwind or any other CSS framework that you're comfortable with. I'm also going to use some custom CSS that I've written. I've prepared some template files that we'll use for the rest of this series. Uh they use the same concepts that we've already learned, conditionals and for loops, but just with more of a complete HTML structure and styling. So, now I'm going to replace our simple uh layout.html here with a more complete version and I have a file that I've moved over into my project here called layout_finished.html. So, let me open this and copy its contents. And I will copy and paste this into layout.html and I'll go over all of this, don't worry. And again, all of this is going to be available to download and I'll have links in the description section below if you want to follow along with this code exactly. Okay, so this is a lot more code, but let me scroll through here and point out the key parts. So, up here in the head section, we have our conditional title like we already had and now we have some open graph meta tags. These control how your site appears when shared on social media. I include these in every site since I just use these as a starting point. If you wanted to use these two, then you could fill in those content attributes later when your site is deployed. So, we are also loading in some custom fonts from Google Fonts. This just gives us a nicer looking font than the browser defaults. And here we are loading in the Bootstrap CSS from my CDN. Like I said, I think Bootstrap is something that's easy for beginners and most people are already familiar with it. But, you could use Tailwind or any other framework that you prefer. So, down here, we are loading in a custom CSS style sheet. Now, this is loaded in from {forward-slash} static CSS. Now, we haven't set up our static directory yet. So, this isn't going to work right now, but we'll fix that in just a second. So, then if I keep scrolling down, we can see more static files. We just have some favicon links uh which are icons that appear in the browser tab. And here in the body, we have a navigation bar using Bootstrap classes. So, we can see that we have a navbar class here. Navbar expand for responsive layouts that comes with Bootstrap built in. And a lot of these are just Bootstrap classes that style everything. It looks like a lot, but it's just for styling purposes. So, if I scroll down here, where did it go? Oops, I haven't got there yet. If I keep scrolling down down to our body, then we can see that somewhere we have our content block. And okay, I'm blind. Where is it? The content block. It's going to be in our main section. Oh, it's right here. I was scrolling right past it the entire time. So, this is our content block here where our child templates are going to fill in their content. And then we have a sidebar here that just has some placeholder content. You can do with that whatever you want. At the bottom here, we have a footer that's just setting a copyright. We're using JavaScript to fill in that year automatically. And then we also load in any JavaScript for Bootstrap here. And then we have a simple dark mode toggle between light and dark themes because it is 2026 and we got to have dark mode these days. So, that's for our layout. Now, for our home.html, let me also update that with a complete version. So, I also have this home finished.html. Let me update that. You can see that this is a lot less here than we had for the layout. So, here I'm going to paste this in. Now, let's look at this. So, this is much simpler and it's the same concepts that we were looking at before. We're just extending the layout. We are creating this content block here. We're then looping over our posts. And then we just have some more HTML elements to be more syntactically correct and adding some styles to that. And then you can see here that we have the post author and the date that it was posted, the title, the content, things like that. Okay, so if I save this now, if I reload this in the browser right now, okay, actually I had a point to make and that shouldn't have worked. I think it's because from where I showed the There we go. Okay, so I had to do a hard refresh there. From where I showed you the complete site in the first video, it was caching that CSS. So, I did a hard reset and now it can no longer find our CSS file because we haven't mounted our static directory yet. And we should be able to notice this. If I reload the page here again, then I should be able to go back to our code here. And if I look at the latest request down here in our development server, we can see all these 404s. And that is because it's looking in the static directory here and saying, "Hey, I can't find this CSS file. I can't find this icon. I can't find this picture." All of those are returning 404 not found. So, let's go ahead and set up those static files. So, static files are things like our CSS, JavaScript, images, icons, things that don't change dynamically. They're just served as is. So, first, let me show you the static files that I've prepared here. So, I have a static finished directory here. Let me actually open this in finder and show you what this looks like. I'll make this a little bit larger here. So, here we are in our project directory. I have this static finished folder here that I've dropped in. And within here, we have CSS. It just has one file that is main.css. We have some JavaScript. This is just an empty utils.js right now. Nothing's in there. We have some icons that we're using for the site. You can put your own icons in there. And for profile pics, this is just a default picture here that we're using for all users so far until we get a database set up. And then I also have a site manifest file there. You don't have to worry about that. That's for basically progressive web app support. That might be overkill for tutorial that I've added those in, but it just gives you a complete starting point. If you want to use this for your own project, these are basically the files that I use anytime I'm creating a new site. So, I figured I'd just add them all in here for you all to use. So, you can look up what a site.webmanifest is on your own time if you want to update that. But now, let's use this as the static folder for our website here. So, I'm going to rename this to static instead of static_finished. And now, let's go back to our page here. And now, let me go ahead and close down the sidebar there. Now, we need to tell FastAPI to serve that static directory. So, in main.py, I need to import static files and mount the static directory. So, up here at the top, I'm going to say from fastapi.staticfiles, and I'm going to import static files. Okay. And now, down here below our app, I'm going to go ahead and mount this static directory. So, I'll say app.mount and I'll just say {forward-slash} static. I'll explain what all these are here in just a second. But for the second argument here, it's going to be static files. I'm going to pass in the directory here. And that is going to be directory of static. And then lastly, we'll have a name here and I'll set the name to static as well. So, this mount method takes three arguments. So, the first one here is the URL path where the static files will be accessible. The second one is a static files instance here that's pointing to our static folder, our static directory. And the third one here is a name that we can use to reference in our templates. So, now any file in our static folder is accessible at {forward-slash} static in the browser. So, if I have main.css that's within a CSS directory that's within the static directory, then that'll be accessible at {forward-slash} static {forward-slash} CSS {forward-slash} main.css. So, let's go ahead and take a look at that. So, let me go ahead and do a hard refresh here again. Now, this is working and it should be working this time. It's not just a cached version. So, now we can see that this is looking a lot better. We have a navigation bar here at the top. Our posts are nicely styled. We have our filler sidebar here and the dark mode toggle here that we can use to switch between light and dark or just set it to auto. So, this looks nice and the files are loading correctly, but let me show you one more thing about static files and navigation. So, right now, our navigation links are using hash symbols for navigation. So, to show you what I mean, let me go to the layout here. So, if I scroll up to the top, then for our navigation here, we are just using these hash symbols here for the href and that just makes it a dead link. It's just a placeholder. So, we're going to update these to use URL for, which is the proper way to generate URLs in templates. So, there's two different use cases for using URL for in templates. So, first for route links like navigation and second for static files like CSS, JavaScript, and images. But the benefit of using URL for is that if you ever change your routes or change the mount path from {forward-slash} static to something else, then all the links will update automatically. It's more flexible and follows best practices. So, right here in our navigation of our layout, instead of just that hash placeholder, I'm going to change this and I'm going to use those double curly braces and I'll say URL for and we will just say that this is the URL for home. And now, let me copy that. And I'm also going to set that as the home link as well. So, when we're using URL for on a specific page, you can see that we're passing in the function name there. If I go back to main.py, this home here is what we are passing in as that URL for. Now, I also want to update these static file references to use URL for as well. So, if I go up and look at my CSS here, we can see that currently this is hard-coded in with static CSS main.css. So, this is going to be a little bit different here. So, I'll paste in what we had before. I'll still leave that hard path right there. So, I'll say URL for static, okay? And now, inside of the URL function there, I'm going to say that the path within static is equal to and we already have static there. So, now we just need this second part here, which is the CSS directory and then main.css. And now I can get rid of that hard-coded path there. So, now I'm going to go through and I'm going to upgrade update the rest of these static hard-coded URLs here. I don't want to waste your time, so I'm going to do that really quick and then fast forward here. Okay, so I updated all of those favicons there to use this URL for static. Now, in the home.html, we have a static file as well. It is the profile picture for the user and right now we're just using the default. So, let me replace that as well. So, that goes to profile pictures default.jpeg and then I'll get rid of that. Okay. And also in our layout.html, we do have a login and a register route here as well. Those are right here, but I'm going to leave these as placeholders for now. Because if you use URL for on a route that doesn't exist, then it's going to throw an error. So, we'll add those routes later in the tutorial. So, now if we save everything and then uh test this. So, I will save that, go back to the browser here and load this up. What is the issue that we are having? Oops, some of you may have seen this, but it looks like I forgot to put the path on some of these. So, actually on a lot of these. So, what I need here is path equals. So, sorry about that. So, path equals as that second argument. And I probably did that here too as well, didn't I? So, let's try to rerun this again. Now it looks like it's working. Okay, so it was able to find all those static files and everything with our URL for function in those templates. Now, one thing I want you to notice here, whenever I click home, I don't know if you can see here, but it's actually going to forward/post. So, if I reload this, click on either of these, it's going to forward/post. Okay, now both routes work. If you remember, the post route and the root are basically the same thing. That's not our API post route. But why is it doing that? Why does URL for home go to post? And what if I wanted that to go to the root instead? So, this is happening because, if you remember, in our main.py here, our home route has two decorators pointing to the same function. By default, FastAPI uses the function name as the route name. But since both routes are attached to the same function and that name isn't unique, so URL for just ends up going with this second route here at post. But we can actually fix this by giving each route an explicit name. So, with this right after include_in_schema is equal to false, I can say name is equal to home for then I'll set name is equal to post for this forward/post route there. So, now this forward/root route is explicitly named home and the post route has its own name. So, now when we use URL for, it will use our explicit names here. So, now if I save that and rerun this here in the browser, and if I click on home, we can see that that goes to the root of our website. Okay, so now let me do one final check to make sure that everything is still working here. So, let me go back. Let's reload that. That looks good. Let's check out our post API import endpoint, sorry. So, that's still looking good and in our docs, if I reload this, then we can see that we're still just getting that one API route and that the home routes are not showing up there because we have that include_in_schema equal to false. So, we still have a clean separation there. So, let's recap what we did here. So, we created this templates directory and we configured FastAPI to use that. And then we passed data to our templates through this context dictionary here. And we used the Jinja2 syntax with for loops for iterating, double curly braces for displaying variables, and if statements for conditionals. We implemented template inheritance with layout.html as the parent template so that we don't have to repeat our HTML structure everywhere. We added in our own custom styles and bootstraps for responsive styling. And we also set up static files in our static directory and that's what serves up our custom CSS, JavaScript, which we don't have yet, but we'll be adding later in the series, images and icons and things like that. We used URL for for generating URLs to both our routes and the static files. And now we have a good-looking front end with an HTML display for our data and that's split off from the JSON back end that we're going to use for our API. Now, in the next video, we're going to learn about URL parameters and how we can use those to grab specific resources from our data. So, for example, instead of returning all of our posts, so here we can see that we're returning all of our posts at once. Instead, we can use path parameters to grab a single post instead. So, we'll create both an API endpoint and a template page for viewing individual posts and make the post one our homepage clickable. And we'll learn about type validation with proper error handling as well. But if anyone has any questions about what we covered in this video, then feel free to ask in the comment section below and I'll do my best to answer those. And if you enjoy these tutorials and would like to support them, then there are several ways you can do that. The easiest way is to simply like the video and give it a thumbs up. Also, it's a huge help to share these videos with anyone who you think would find them useful. And if you have the means, you can contribute through Patreon or YouTube and there are links to those pages in the description section below. Be sure to subscribe for future videos and thank you all for watching.

Original Description

In this Python FastAPI tutorial, we'll be learning how to use Jinja2 templates to create an HTML frontend for our API. Templates allow us to serve proper HTML pages to users while keeping our JSON endpoints intact for the backend API. We'll cover setting up Jinja2Templates, passing data to templates, using Jinja2 syntax for loops and conditionals, implementing template inheritance with a layout file, adding Bootstrap for styling, and configuring static files for CSS and images. By the end of this video, we'll have a nicely styled blog homepage that displays our posts. Let's get started... The code from this video can be found here: https://github.com/CoreyMSchafer/FastAPI-02-Templates Full FastAPI Course: https://www.youtube.com/playlist?list=PL-osiE80TeTsak-c-QsVeg0YYG_0TeyXI ✅ Support My Channel Through Patreon: https://www.patreon.com/coreyms ✅ Become a Channel Member: https://www.youtube.com/channel/UCCezIgC97PvUuR4_gbFUs5g/join ✅ One-Time Contribution Through PayPal: https://goo.gl/649HFY ✅ Cryptocurrency Donations: Bitcoin Wallet - 3MPH8oY2EAgbLVy7RBMinwcBntggi7qeG3 Ethereum Wallet - 0x151649418616068fB46C3598083817101d3bCD33 Litecoin Wallet - MPvEBY5fxGkmPQgocfJbxP6EmTo5UUXMot ✅ Corey's Public Amazon Wishlist http://a.co/inIyro1 ✅ Equipment I Use and Books I Recommend: https://www.amazon.com/shop/coreyschafer ▶️ You Can Find Me On: My Website - http://coreyms.com/ My Second Channel - https://www.youtube.com/c/coreymschafer Facebook - https://www.facebook.com/CoreyMSchafer Twitter - https://twitter.com/CoreyMSchafer Instagram - https://www.instagram.com/coreymschafer/ #Python #FastAPI
Watch on YouTube ↗ (saves to browser)
Sign in to unlock AI tutor explanation · ⚡30

Playlist

Uploads from Corey Schafer · Corey Schafer · 0 of 60

← Previous Next →
1 Web fonts using CSS Font Face
Web fonts using CSS Font Face
Corey Schafer
2 Using Font Awesome in Desktop Applications (OS X)
Using Font Awesome in Desktop Applications (OS X)
Corey Schafer
3 Sublime Text 2: Setup, Package Control, and Settings
Sublime Text 2: Setup, Package Control, and Settings
Corey Schafer
4 ArcGIS API for JavaScript Part 1: Our First Web Map
ArcGIS API for JavaScript Part 1: Our First Web Map
Corey Schafer
5 Mac Tip: Windows' Snapping Feature on Mac with HyperDock
Mac Tip: Windows' Snapping Feature on Mac with HyperDock
Corey Schafer
6 Linux/Mac Terminal Tutorial: Creating Aliases for Commands
Linux/Mac Terminal Tutorial: Creating Aliases for Commands
Corey Schafer
7 ArcGIS API for JavaScript Part 2: Starting Templates
ArcGIS API for JavaScript Part 2: Starting Templates
Corey Schafer
8 Paver Patio Time Lapse
Paver Patio Time Lapse
Corey Schafer
9 Mac Tip: Ways to perform Screen Capturing and Screenshots
Mac Tip: Ways to perform Screen Capturing and Screenshots
Corey Schafer
10 WordPress Plugins: Imsanity
WordPress Plugins: Imsanity
Corey Schafer
11 WordPress Tips: Test your theme with Theme Unit Test and Monster Widget
WordPress Tips: Test your theme with Theme Unit Test and Monster Widget
Corey Schafer
12 Sublime Text 3: Setup, Package Control, and Settings
Sublime Text 3: Setup, Package Control, and Settings
Corey Schafer
13 Understanding Binary, Hexadecimal, Decimal (Base-10), and more
Understanding Binary, Hexadecimal, Decimal (Base-10), and more
Corey Schafer
14 Mac Tip: Adding Folder Stacks to the Dock
Mac Tip: Adding Folder Stacks to the Dock
Corey Schafer
15 CSS Tips and Tricks: Add External URLs to Print Stylesheets
CSS Tips and Tricks: Add External URLs to Print Stylesheets
Corey Schafer
16 JavaScript Arrays: Properties, Methods, and Manipulation (Part 7 of 7)
JavaScript Arrays: Properties, Methods, and Manipulation (Part 7 of 7)
Corey Schafer
17 JavaScript Arrays: Properties, Methods, and Manipulation (Part 1 of 7)
JavaScript Arrays: Properties, Methods, and Manipulation (Part 1 of 7)
Corey Schafer
18 JavaScript Arrays: Properties, Methods, and Manipulation (Part 5 of 7)
JavaScript Arrays: Properties, Methods, and Manipulation (Part 5 of 7)
Corey Schafer
19 JavaScript Arrays: Properties, Methods, and Manipulation (Part 4 of 7)
JavaScript Arrays: Properties, Methods, and Manipulation (Part 4 of 7)
Corey Schafer
20 JavaScript Arrays: Properties, Methods, and Manipulation (Part 3 of 7)
JavaScript Arrays: Properties, Methods, and Manipulation (Part 3 of 7)
Corey Schafer
21 JavaScript Arrays: Properties, Methods, and Manipulation (Part 2 of 7)
JavaScript Arrays: Properties, Methods, and Manipulation (Part 2 of 7)
Corey Schafer
22 JavaScript Arrays: Properties, Methods, and Manipulation (Part 6 of 7)
JavaScript Arrays: Properties, Methods, and Manipulation (Part 6 of 7)
Corey Schafer
23 Python Tutorial: if __name__ == '__main__'
Python Tutorial: if __name__ == '__main__'
Corey Schafer
24 Sublime Text Quick Tip: "Go To Definition" Click Shortcut
Sublime Text Quick Tip: "Go To Definition" Click Shortcut
Corey Schafer
25 How to quickly create favicons for the desktop, Apple/Android devices, tablets, and more
How to quickly create favicons for the desktop, Apple/Android devices, tablets, and more
Corey Schafer
26 Easily Resize Multiple Images Using Picasa
Easily Resize Multiple Images Using Picasa
Corey Schafer
27 Easily Resize Multiple Images Using the Mac Terminal
Easily Resize Multiple Images Using the Mac Terminal
Corey Schafer
28 Python Tutorial: virtualenv and why you should use virtual environments
Python Tutorial: virtualenv and why you should use virtual environments
Corey Schafer
29 Python Tutorial: pip - An in-depth look at the package management system
Python Tutorial: pip - An in-depth look at the package management system
Corey Schafer
30 Git Tutorial: Using the Stash Command
Git Tutorial: Using the Stash Command
Corey Schafer
31 How Software Engineers, Developers, and Designers can volunteer their skills
How Software Engineers, Developers, and Designers can volunteer their skills
Corey Schafer
32 Git Tutorial: Diff and Merge Tools
Git Tutorial: Diff and Merge Tools
Corey Schafer
33 Git Tutorial: Change DiffMerge Font-Size on Mac OSX
Git Tutorial: Change DiffMerge Font-Size on Mac OSX
Corey Schafer
34 Sublime Text Quick Tip: Launch Sublime Text from the Terminal
Sublime Text Quick Tip: Launch Sublime Text from the Terminal
Corey Schafer
35 Python Tutorial: str() vs repr()
Python Tutorial: str() vs repr()
Corey Schafer
36 Programming Terms: DRY (Don't Repeat Yourself)
Programming Terms: DRY (Don't Repeat Yourself)
Corey Schafer
37 Programming Terms: String Interpolation
Programming Terms: String Interpolation
Corey Schafer
38 Programming Terms: Idempotence
Programming Terms: Idempotence
Corey Schafer
39 Python Tutorial: Namedtuple - When and why should you use namedtuples?
Python Tutorial: Namedtuple - When and why should you use namedtuples?
Corey Schafer
40 Programming Terms: Mutable vs Immutable
Programming Terms: Mutable vs Immutable
Corey Schafer
41 Python Tutorial: Else Clauses on Loops
Python Tutorial: Else Clauses on Loops
Corey Schafer
42 Overview of Online Learning Resources
Overview of Online Learning Resources
Corey Schafer
43 Mac OS X Terminal Tutorial: Time-Saving Keyboard Shortcuts
Mac OS X Terminal Tutorial: Time-Saving Keyboard Shortcuts
Corey Schafer
44 Git Tutorial for Beginners: Command-Line Fundamentals
Git Tutorial for Beginners: Command-Line Fundamentals
Corey Schafer
45 Quickest and Easiest Way to Run a Local Web-Server
Quickest and Easiest Way to Run a Local Web-Server
Corey Schafer
46 Python Tutorial: Generators - How to use them and the benefits you receive
Python Tutorial: Generators - How to use them and the benefits you receive
Corey Schafer
47 Python Tutorial: Comprehensions - How they work and why you should be using them
Python Tutorial: Comprehensions - How they work and why you should be using them
Corey Schafer
48 Chrome Quick Tip: Quickly Bookmark Open Tabs for Later Viewing
Chrome Quick Tip: Quickly Bookmark Open Tabs for Later Viewing
Corey Schafer
49 Programming Terms: Combinations and Permutations
Programming Terms: Combinations and Permutations
Corey Schafer
50 Git Tutorial: Difference between "add -A", "add -u", "add .", and "add *"
Git Tutorial: Difference between "add -A", "add -u", "add .", and "add *"
Corey Schafer
51 Preparing for a Python Interview: 10 Things You Should Know
Preparing for a Python Interview: 10 Things You Should Know
Corey Schafer
52 SQL Tutorial for Beginners 1: Installing PostgreSQL and Creating Your First Database
SQL Tutorial for Beginners 1: Installing PostgreSQL and Creating Your First Database
Corey Schafer
53 SQL Tutorial for Beginners 2: Creating Your First Table
SQL Tutorial for Beginners 2: Creating Your First Table
Corey Schafer
54 SQL Tutorial for Beginners 3: INSERT - Adding Records to Your Database
SQL Tutorial for Beginners 3: INSERT - Adding Records to Your Database
Corey Schafer
55 Linux/Mac Terminal Tutorial: Navigating your Filesystem
Linux/Mac Terminal Tutorial: Navigating your Filesystem
Corey Schafer
56 Python: Ex Machina Easter Egg - Hidden Message within the Code
Python: Ex Machina Easter Egg - Hidden Message within the Code
Corey Schafer
57 Mac Tip: New Split Screen Feature in El Capitan
Mac Tip: New Split Screen Feature in El Capitan
Corey Schafer
58 Setting up a Python Development Environment in Eclipse
Setting up a Python Development Environment in Eclipse
Corey Schafer
59 Git Tutorial: Fixing Common Mistakes and Undoing Bad Commits
Git Tutorial: Fixing Common Mistakes and Undoing Bad Commits
Corey Schafer
60 SQL Tutorial for Beginners 4: SELECT - Retrieving Records from Your Database
SQL Tutorial for Beginners 4: SELECT - Retrieving Records from Your Database
Corey Schafer

This video tutorial teaches how to create an HTML frontend for a FastAPI application using Jinja2 templates, allowing for dynamic data to be passed to templates and proper HTML pages to be served to users. The tutorial covers setting up Jinja2 templates, passing data to templates, and using template inheritance to reduce code duplication. By the end of this tutorial, viewers will be able to create their own HTML frontend for a FastAPI application.

Key Takeaways
  1. Create a templates directory in the project
  2. Import Jinja2 templates from FastAPI.templating
  3. Configure FastAPI to use templates directory
  4. Create a new file for the template
  5. Update the route function to use the template instead of returning raw HTML
  6. Pass data to the template using a context dictionary
  7. Implement template inheritance with layout.html as the parent template
💡 Using Jinja2 templates allows for dynamic data to be passed to templates, making it easy to create an HTML frontend for a FastAPI application.

Related Reads

📰
Bypassing Shadow DOMs & Same-Origin Iframes: How I Solved LinkedIn's Massive SDUI Update
Learn how to bypass Shadow DOMs and Same-Origin Iframes to solve issues like LinkedIn's SDUI update
Dev.to · Maaz Khan
📰
Why Check Then Act Is the Silent Killer in Banking Backends, and How NestJS Prevents It
Learn how 'Check Then Act' can cause issues in banking backends and how NestJS helps prevent it
Dev.to · Peace Melodi
📰
PDF Tamper Detection API for Laravel and PHP: Integration Guide
Learn to integrate a PDF tamper detection API into Laravel and PHP applications to ensure document integrity
Dev.to · Iurii Rogulia
📰
How I Built a Concurrency-Safe Reservation System
Learn how to build a concurrency-safe reservation system using FastAPI, PostgreSQL, Redis, and SQLAlchemy to prevent race conditions
Dev.to · Rahul Chaduvula
Up next
Indian Express Editorial Analysis by Chandan Sharma - 1 JULY 2026 | UPSC Current Affairs 2026
StudyIQ IAS
Watch →