Python FastAPI Tutorial (Part 9): Frontend Forms - Connecting JavaScript to Your API
29:03

Python FastAPI Tutorial (Part 9): Frontend Forms - Connecting JavaScript to Your API

Corey Schafer 26.01.2026 6 676 просмотров 283 лайков

Machine-readable: Markdown · JSON API · Site index

Поделиться Telegram VK Бот
Транскрипт Скачать .md
Анализ с AI
Описание видео
In this video, we'll be adding interactive frontend forms that connect to our FastAPI backend. Up until now, our web pages have been read-only, but we'll change that by using JavaScript and the Fetch API to create, edit, and delete posts directly from the browser. We'll use Bootstrap modals for our forms and feedback messages, keeping users on the current page instead of navigating them away. This tutorial focuses on the API interaction itself and how the frontend sends data to our endpoints and handles responses. Let's get started... The code from this video can be found here: https://github.com/CoreyMSchafer/FastAPI-09-Frontend-Forms 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

Оглавление (6 сегментов)

Segment 1 (00:00 - 05:00)

Hey there. How's it going everybody? In this video, we're going to be adding front-end forms that interact with our fast API backend. So, right now, our API is mostly functional. We can create, update, and delete post using the interactive docs at this forward/doccks route or by making manual requests through curl or similar tools. But our actual front-end web pages are read only. So users can browse post and click into individual post. But there's no way to create, edit, or delete anything from the browser itself. So in this tutorial, we're going to fix that by adding forms that call our API. So we're going to use JavaScript with the fetch API to make those calls. Now, this is a fast API series, so we'll mainly focus on the API interaction itself, showing how the front end sends data to our endpoints and handles the responses. But we will take a brief look at the JavaScript and how it's being used as the glue that connects everything together. And the nice thing about this setup is that any client can use the API the same way. So the JavaScript that we write here uh could just as easily be a mobile app or a desktop app making those same requests. Now, one quick thing to point out before we start, our API currently requires a user ID when creating posts. Uh if I look here, we can see that it requires a user ID to create a post here. Now, we don't have authentication yet. That's coming in a future tutorial. So, for now, we're going to hardcode a user ID in our JavaScript to simulate a loggedin user. So, this lets us test creating, editing, and deleting posts as that user. And for post owned by other users, we'll see what it looks like when someone doesn't have permission to edit or delete. and we'll replace all of this with authentication later on. Now, if you've been following along, you should already have a user and some post from the previous tutorials. If not, then you'll need to create a user and at least one post using the docs interface here before continuing on. I currently have a user with an ID of one, and I'll be using that as my hard-coded user ID throughout this tutorial. Now, throughout this tutorial, we're going to be adding some Bootstrap modals. If you don't know what a modal is, uh, let me show you really quick. So, I have one in our application here, but it's not hooked up to anything yet. So, if I click on one of my posts and then I click on delete, then you can see that I get this popup. Now, this popup is just called a modal. So, we'll be adding some of these throughout uh the video for creating posts, success and error messages, and things like that. All right, so let's go ahead and get started with building the front end. So we're going to start with creating post. So instead of embedding a form directly on uh a specific page, we're going to add a modal to our layout template. And this is going to be better for us because it makes the form accessible from any page in the application. So in my templates here, let me open up layout here. So by adding this functionality to our layout, users will be able to create posts from the homepage, from individual post pages, uh from anywhere. And the modal keeps users where they are and doesn't navigate them away from what they're already doing. So this is my layout template here. Let me scroll down to our current navbar. So here we have our navbar and right here are the login and register routes. So right before the login button, I'm going to add a new post button that opens a Bootstrap modal. Now just like the rest of the series so far, I know you all want most of the focus to be on fast API and the backend API. So, for the HTML and JavaScript, I'm going to be using some snippets that I can copy and paste, but we'll go over everything once it's added in and see how it interacts with our API when it does. So, I've got this snippet ready here. So, let me go ahead and grab this. So, I will copy all of this for this new modal here. And I will paste this into our layout right before our login and register buttons. So, this is a bootstrap button that triggers a modal. The databs toggle here equals modal tells Bootstrap that this button opens a modal and datab target here specifies which modal to open. We're using the same styling as the login button with the button outline light here. And again, the reason that we're putting this in the base layout is because we want users to be able to create posts from anywhere and not just on the homepage. Once we have authentication set up, then this button will only be visible when the user is logged in. But for now, everyone's going to be able to see it. Okay. So now we need to actually add that modal. So I'm going to scroll down here near the bottom of layout. html right below the footer here. This is where I'll add that modal in. And it's a good bit of HTML. So let me grab this here and then we will discuss it. So I'll grab that and paste that in here. Okay. So this is a standard Bootstrap modal with a form inside. And the form

Segment 2 (05:00 - 10:00)

is the important part here. So let me scroll to that. So let's go ahead and walk through this. So the form has an ID of create post form which is important because we'll reference this in our JavaScript. So we have inputs for the title and content. And both of these have these uh required attribute for basic browser validation. Now notice there's no user ID field. Uh we're not going to show that to our end user. We'll hardcode that into the JavaScript for now. Also notice that the form doesn't have an action or method attribute. That's because we're going to intercept the submission with JavaScript. This gives us control over the process. So we can call the API, show feedback in a modal, and then decide when to reload the page. And the modal footer down here has a cancel button that dis dismisses this and a post button that submits the form. So now we need a nice way to show feedback to the user. So if a post gets created successfully then we want a success message. And if something goes wrong like validation fails then we want to have a nice error message. So right after the create post modal here I'm going to add in two more modals. Now there's a lot of nested divs here. So let me just go ahead and uh minimize that so that I can see exactly where I'm at here. Okay. So I'm going to add two more modals here and one of these is going to be for success and one of them error. So here in my snippets I've got two of these here and these are basically the same thing here. So let me save that. So these are pretty standard here. The success modal has a green header and contains a paragraph that has this success message ID here. And the error modal has a red hair uh header and the paragraph contains this error message ID here for error details. So we'll be using JavaScript to grab these IDs and fill these in later. And we're putting both of these in layout. html as well so that they are also available on every page. Now before we wire that up, I want to create a small JavaScript utilities module. We are going to use some of the same logic across different pages. So, it makes sense to put all of that in a shared place. So, let's open this static folder here. You can see I have a JavaScript directory in here and we have this utils. js. Mine already exists, but it's empty. But if you don't have a JavaScript folder or this utils file in your static folder, then you can go ahead and create that. And within here, I'm going to paste three different utility functions here that we're going to be using throughout this series. So, let me grab all of these here. Now, I know that this is a lot of copying and pasting here, but a lot of this stuff isn't really interacting with our API yet, and that's really what I focus on. This is kind of just front-end setup type of stuff. But, let me explain each of these just so we have a basic idea of what's going on here. So, first we have this get error message function. Now, this is a big one because fast API validation errors aren't a simple string. So sometimes detail can be a string like when we get post not found but validation errors can also be a list of error objects and if we just dump that into the UI that's when you get stuff that you may have seen on some websites where you get this weird object that leaks through and it just looks like code in an error message. So this handles extracting userfriendly uh messages from our API responses. Now if detail is a string we just return it directly here and if it's an array of validation errors then we extract the messages and join them together. So second we have this show modal function here. Now this is just a helper function that I'm going to use that uses Bootstrap's get or create instance method here uh to get or create my modal instance and then show it. So we just pass in the modal ID as a string and it returns and shows that modal. Same idea for this helper function here for hide modal. Uh this gets an existing modal and hides it. And it safely handles cases where the modal doesn't exist. And you can see that we're exporting all of these functions so that we can import only what we need in each template. Okay. So now let's wire up the create post form with JavaScript. Now this is where we're going to start using uh JavaScript to interact with our API. So, we want this handler to exist on every page because the modal is on every page. So, we'll put this script in the base of layout. html here. So, I'm just going to scroll down to the bottom here and after our dark theme down here. So, this is where I'm going to add our script. So, let me go right here before the closing body here. And now I will add a script. And this is where we're going to set up that functionality to

Segment 3 (10:00 - 15:00)

create a post. Now I have this in my snippets as well. So we can see that I have this written out here and all of this is going to be available for download and I'll have that in the comment section below. So if I save this and scroll up here then let me go ahead and walk through this because this is going to be the core pattern uh that we'll use for all of our forms. So I have comments throughout the JavaScript here, but we're still going to go over everything. So first we're using the type module here on our script tag, which lets us use import statements. So we import our utility functions from utils. js and then we grab the form by ID here and that is create post form is the one that we're grabbing here. And then on that form, we are listening for the submit event. Now when the form is submitted, we call event. prevent default. So this stops the web browser's default form behavior and lets us handle the submission ourselves with JavaScript. So then we gather the form data. So new form data here grabs all of the form values for us and object. f from entries here converts that to a plain object like here title is equal to this content now next we are adding a hard-coded user ID here now this is that temporary scaffolding that I was mentioning so once we add authentication then this is going to come from the authenticated users token instead of this value here so then here is where we are trying to use the fetch API I to post to API post here. So we set the method to post the content type header to application/json because our API expects JSON and we stringify our post data as the body. Now if the response is okay then we parse the JSON. We set the success message. And then we just hide that create post modal and instead show the success modal and then we clear the form. And then right here we're setting up an event listener to reload the page when the success modal is closed. So this ensures that the new post shows up in our list of posts. Now if we get an error response then we parse that error and we use our get error message function to extract a userfriendly message and then hide the create post modal here and show the error modal. Now if there's some other error like a network error or the API is down then we also catch that and show a generic network error message here. So it just says network error please check your connection and try again. Now, also notice at the end here, we added this block scripts section. This lets child templates add their own scripts that will load after Bootstrap is ready. And we'll use this for the post page. All right. So, let's save this and test it out. So, I'm going to save our layout. html here. And now, let me go back to the browser and reload this. Okay. So, we can see that we get this new post button up here. Let me click on this. And our modal opens up. Now, let me fill out a test post. So, test post uh from front end frontend post. And if I go ahead and post this, then we can see that we get our success message. And now, if I close that success message, then our page reloads and we can see that our new post is down here at the bottom. Okay. So, that highlights a little bit of an issue here. Uh because by default, our database returns posts in the order that they were created. Usually this is oldest to newest, but for a blog or a social feed like this, we almost always want to see the newest post first. So whenever I posted this, I would have liked to have seen this up here at the top. So where should we fix this? So we could fix it in the JavaScript by sorting the post on the front end, but the best practice is to handle this on the back end. Uh business logic belongs in the back end. So database sorting with orderby is much more efficient than JavaScript sorting and it's consistent across all the clients and it's also going to be our single source of truth. So let's update our backend code to sort post by date and we're going to update uh four functions in order to do this. So let me open up our code here. So we have to think about where we are getting lists of post returned back to the user. So right off the bat, we know that in our post route, we are going to have these. So down here in get post, we can see that we have a list of post responses here. So let's just update our query here to add an order by. So I'll say that we want to order by and we want

Segment 4 (15:00 - 20:00)

say that we want to order by and models. post dot date posted. And this is going to be in descending order. So this tells SQL Alchemy to order by the date posted field in descending order which means the newest first. So this uh descending here method gives us descending order. Without it, we would get ascending order by default which is oldest first. So now let me go ahead and copy this because I'm probably going to need it again. And now let's go back to our main. py file here. And I know in our home route here, we also are returning a list of posts here. So, let's go ahead and add that order by in here as well to our query. So, I will add that in there. And while we're in main here, I know that there's a couple of more. A post page is just a single post, so we don't need that. Now, a user's post page. This is going to be all of the posts for a particular user. There's going to be multiple here. So right after this wear clause here where we're grabbing the post by that particular user, we will also order these by descending. And finally, one more place that I can think of here, which will be the last one that we update. If we go to our user routes, and we look at our get user post for the API. So right here, we can see that we are also returning a list of posts here. So, right down here, I will also do the order by here as well. Now, I went through and wrote down all of those locations that I needed to update. But if you didn't know where to start and you had a program where you had to add change the ordering of a bunch of different queries, then you could just search your entire project for something like db. execute and just search where you're doing queries and where you would need to add those orderby statements. Okay, so now all of our post listings should be consistent and show the newest posts first. So I saved all of our files here. Let's go back to the browser and reload this. And now when I reload this, we can see that our test post from the front end is now our first here. And if I click on my user, then we can see that the newest post is at the top there as well. And just for a sanity check here, if I look at the actual API, we can see that here uh we have this 113 post up here. If I reload this now, then we can see that now the top one is this 123 post, the uh post from the front end. Okay. So now let's add the ability to edit and delete posts. So if I click on an individual post here, we can see that we have edit and delete buttons, but these currently aren't wired up. So let's go ahead and look at the current HTML that we have for this here. So this is in our post template. So in our templates here, I'll open up our post template here. And now if we look at the current file, we can see that there's already a post actions div here with a placeholder edit and delete button. Now the edit button is just an anchor tag with an href uh set to this hashtag here. And that just means that it currently doesn't do anything. Now the delete button opens up a placeholder modal here that I showed you earlier. Now we're going to replace all of that with our new JavaScript driven version. So first let's delete the existing post actions div here. And also I'll go ahead and delete the to-do comments around it here. So I will just grab all of this and delete that. And now I'll go to my snippets here and grab our new version. And this is going to wrap everything in a conditional so that it only shows for our temporary user. So let me paste this in and then walk through this here. So right now we're only showing these buttons if the post do user ID is equal to one. Now in the O tutorial like I said before this will become if the current user's ID equals the post author's ID. So the buttons use the same bootstrap toggle and target data attributes that we used for the new post button to open their respective modals. So now we actually need those modals for these actions. And I'll add the edit modal right after the article element closes here. So right here I'll go ahead and add in our edit modal. So let me grab this and I will go ahead and paste this in here. Let's take a look at this. So this modal is similar to the create modal but with a few important differences here. So first our form down here has the ID of edit post form so that we can reference it separately in the JavaScript. There is a hidden input

Segment 5 (20:00 - 25:00)

with a post ID here. And one important thing here is that the title and the content, these fields are prefilled with the current post title and the current post content. That way when the user opens the form to edit it, they go already see the current data in there. Now for the delete uh confirmation modal, if you look at post HTML here, there's already a delete modal in here. Now, this one was set up as a placeholder, and we're going to replace this with a working version that actually calls our API. So, delete the entire existing delete modal here. And then we will paste in our updated version. And just so I don't grab the wrong stuff here, let me go ahead and make sure I'm only grabbing that. And now, let's paste in our completed version here. So, I'll grab this and paste this in here. Okay. So, looking at this here, we can see that we have an ID here. Uh, it is our actual delete button. Down here, we have an ID here of confirm delete. We'll use that in JavaScript. It's just a regular button. It's not a form. And the rest of this is pretty standard for, you know, dangerous activities like deleting something. So, this background danger here is just a red header for the modal. Uh, and then we have a confirmation here that just says, are you sure that you want to delete this post? This can't be undone. But all of this modal stuff in the HTML is just that. It's just HTML. Now, we need the JavaScript to handle the edit and delete. So, we're going to use the blocks script that we defined in layout. html. Uh, at the end of post. html here, after this end block content, this is where we can add our scripts block. So, in our snippets here, let me grab the scripts block that we are going to use. And this is the last thing that we're copying and pasting for this video. So, let me paste this in here and walk through both of these. So, since we're using this scripts block here, this is going to add this to that block script section that we added to our layout template. So, that means this script loads after Bootstrap is ready. uh we import the same utilities from utils. js here. We get the post id directly from the ginga 2 templating. Now for our edit form here we add a submit event listener. We prevent the defaults from submission. Then we gather the form data. We remove the post ID from the data since it's in the URL and not the body. And then down here is our API stuff. So we are trying to use the fetch API to send a patch request here to API post with that post ID. Now we're using patch instead of put because we're only doing a partial update. We're sending the title and the content but not the user ID. So patch is semantically correct for partial updates. Now if the response is okay then we show the success modal and reload it when it closes. We've seen this earlier and if we get an error then we show the error modal after we parse that error message. And lastly we have the network error down here at the bottom. Now for the delete modal and this is actually for that delete button within the modal specifically. We add a click event listener here. We send a delete request to slash API/post slash that post id. Now there's no body that's needed for a delete. Uh the post ID in the URL identifies what to delete. Now if the response status is 204, which means it's a success with no content, then we redirect to the homepage. The post no longer exists, so we can't stay on that page. And just like before, if there is an error, then we parse that error and show it in the error modal. And we also have our network error down here as well. Okay. So now let's save everything and test this out. So if I go to our browser here, let me reload this. And now let's create a new post here. So for the new post, I'll just say uh new post with all functionality. And then new post done. We will add that. It says it was successful. We can see that it goes to the top there. Now let me click this. Let's see if we can edit this post. New post with edit functionality. Let's save that. It reloads that page. And we can see

Segment 6 (25:00 - 29:00)

that edit worked. And now let's try to delete this post. So if I say delete, it says are you sure this is permanent? Can't be undone. Go ahead and delete that. And if I look back at the front end here, we can see that post is no longer there. So all of our CRUD operations are now fully functional from the front end here. So now let me show you the error handling uh that actually works. So if I go to add a new post here and I just type in, you know, very long title and then I copy this and paste it a bunch of times. If you remember, our titles have I think it's 50 characters max. Testing length. And if I try to post this, well, actually, it's not 50 characters. It is 100 characters. It tells us right there. So, our schema has a max length of a 100 characters for titles. So, we typed in more characters than that. Tried to submit it, and it's telling us that we went over the limit there. So, the error handling and validation is working well from the front end as well. Okay. So all of that is looking good. Okay. So let's talk a little bit about what we just built here. So the key thing is the separation of concerns. So the backend handles the data, the validation and the business logic through our JSON API and the front end handles presentation and user interaction. And because our API returns JSON, the same API can serve multiple clients. Right now, we're using it in a web browser, but a mobile app could use the exact same API. A desktop app could use it. Uh we could even use it within the command line, whatever we wanted. Now, we're not building a full single page application here like a React app. Uh after successful actions, we still reload the page, but we do get some nice benefits from this hybrid approach. So, forms appear in modals, so users stay on their current page. error messages are appearing in modals too instead of redirecting to an error page. And most importantly, we have the clean API separation that makes our backend reusable. So, it's a nice practical middle ground that we have uh that a lot of other real world applications use and it's a foundation that you can build on if you want more dynamic behavior later on. Now, the main thing with our application right now is that all of those hard-coded user ID values aren't secure. So, anyone could call our API directly and create, edit, or delete just about anything. So, in the next tutorials, we're going to fix that with authentication. So, users will register and log in with JSON web tokens. The user ID will come from the token automatically, and the API will verify ownership before allowing edits and deletes on any post. So, it's going to be satisfying to replace all these hard-coded ones with actual proper authentication. But, I think that's going to do it for this video. Hopefully, now you have a good idea of at least one example of how we can connect a frontend to our API using JavaScript and the fetch API. In this case, like I said, in the next tutorials, we'll add authentication to make this secure. We'll have user registration and login, JSON web tokens, and we'll remove all that temporary scaffolding that we currently have. 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.

Другие видео автора — Corey Schafer

Ctrl+V

Экстракт Знаний в Telegram

Экстракты и дистилляты из лучших YouTube-каналов — сразу после публикации.

Подписаться

Дайджест Экстрактов

Лучшие методички за неделю — каждый понедельник