LongCut logo

Learn Fast API With This ONE Project

By Tech With Tim

Summary

## Key takeaways - **FastAPI auto-generates interactive docs**: FastAPI automatically creates fully interactive API documentation at /docs and /redoc where you can test endpoints directly by pressing 'try it out' and 'execute'. This is the coolest feature of FastAPI. [28:11], [29:15] - **ImageKit handles all media complexity**: ImageKit manages image/video upload, optimization, cropping, and transformations via simple URL parameters like tr=w-500,h-300 or e-contrast, eliminating the pain of manual media handling. Backend uploads via ImageKit API return URLs with full metadata. [01:10:27], [01:24:20] - **JWT tokens via FastAPI-Users**: FastAPI-Users automatically generates complete JWT authentication system including login/register/reset endpoints at /auth/jwt - just include the router and add current_active_user dependency to protect routes. Users get tokens that identify them for all subsequent requests. [01:30:54], [01:45:14] - **SQLAlchemy async ORM setup**: SQLAlchemy async ORM replaces in-memory dictionaries with persistent SQLite database using declarative_base models, async_sessionmaker dependency injection, and simple session.add/commit/refresh pattern for CRUD operations. Models auto-create tables on startup. [46:30], [01:04:01] - **Pydantic schemas validate everything**: Pydantic BaseModel schemas automatically validate request body data, generate perfect docs, and enforce output types - FastAPI rejects invalid data before functions execute and documents exact response schemas in /docs. [43:28], [45:56] - **Dependency injection simplifies DB access**: FastAPI's depends() injects database sessions and current_user automatically into every protected endpoint - just add session: AsyncSession = Depends(get_async_session) and user: User = Depends(current_active_user) to access database and authenticated user. [01:01:39], [01:52:24]

Topics Covered

  • APIs Secure Data Access Layer
  • FastAPI Auto-Docs Transform Development
  • Dependency Injection Automates Sessions
  • ImageKit Backend Uploads Secure Control
  • JWT Tokens Stateless Authentication Wins

Full Transcript

In this video, I'll teach you Fast API by working through a real project. I'll

go over everything from the absolute basics to some more advanced concepts like setting up authentication, logging in various users, connecting to a database, and all of the components that you actually need if you want to build a

real production-grade application. Now,

that said, this video is not designed for absolute beginners. While I will teach you everything from scratch as it relates to APIs and kind of web app development, I'm going to assume that you have some experience in Python. That

said, let's quickly have a look at the finished project and then we'll get into some of the theory and start writing some code. So, the project we'll be

some code. So, the project we'll be building here is a simple photo and video sharing application. Think of it like the really early days of Instagram except it won't have nearly as many

features. Now, the way this works is you

features. Now, the way this works is you can sign in. So, I've set up a really simple user interface here in something called Streamllet. We'll talk a little

called Streamllet. We'll talk a little bit about that later in the video, but this isn't going to be focused on building the interface. It's more going to be focused on the back end and the logic and the well API with fast API.

So, you can see that I was able to sign in here and then immediately I'm brought to a feed where I can see some different photos. I can see the date they were

photos. I can see the date they were posted and the user that posted them.

And then I also have some videos as well. Now, you have the ability to

well. Now, you have the ability to upload something. So, for example, if

upload something. So, for example, if you were to come here and let's just pick maybe a random photo that we have here. Okay, let's just go like this and

here. Okay, let's just go like this and call this thumbnail. And then we share it. It's just going to take a second.

it. It's just going to take a second.

And then this will be uploaded to our feed. So right now it's just uploading

feed. So right now it's just uploading the video. And if we go back to the feed

the video. And if we go back to the feed here, we should see the photo app. And

you can see the photo shows up by us and that it's on today's date when I'm recording this video. Okay, so that's the application. I know it seems pretty

the application. I know it seems pretty basic, but I promise this is going to teach you a ton of concepts that you need to understand as it relates to fast API. And I think the most important

API. And I think the most important thing is all of the authentication and authorization which most people skip in these beginner type tutorials. So with

that said, let's hop over to this myro board that I put together because I want to start going through some theory that's really important to understand before we can even start building APIs.

And by the way, as we get later into the video and we're going to start setting up the images and videos, that is notoriously pretty difficult to do. In

order to do that effectively, we're going to use today's sponsor, Image Kit.

Don't worry, they are free to use and play with. you don't need to pay for

play with. you don't need to pay for them and they just make this process significantly easier. So big shout out

significantly easier. So big shout out to them, but more on that later. Okay,

so let's get into the video. Now, we're

going to use fast API, right? This is

fast application programming interface.

That's what API stands for. Now, this is essentially a back-end framework. What

that means is that this is going to be running on some type of server and it is going to be essentially controlling data. All an API really does for us is

data. All an API really does for us is it facilitates the access and control of data. In our case, it's going to be

data. In our case, it's going to be image or video posts, right? Or

different user accounts. But before we can get into all of that, we need to start understanding some kind of core concepts of web apps in general. So,

let's start by talking about URLs and endpoints so that we can get the terminology out of the way. Now, this

whole thing right here and this one as well is a URL. You've seen this, you know, millions of times before, especially when you've browsed to a website. And I want to just go over the

website. And I want to just go over the components of the URL so that we understand what they are. Now the first is the domain. Okay, the domain is essentially the website, you know, the

space of the URL. So training.devlaunch

us. This is our domain. techwithim.net.

This is the domain. The domain will typically end in like us or.com or.net or.ca or something along those lines.

or.ca or something along those lines.

Now after the domain, you have what's referred to as the path or sometimes called the endpoint. Now, this is the particular route or kind of the page or resource that you're going to be accessing from this domain. So, for

example, we have training.devaunch.us/tim.

training.devaunch.us/tim.

So, I'm going to the /tim page right here. /courses/python.

here. /courses/python.

So, I'm going to the python courses page right. And for a typical website, these

right. And for a typical website, these make a lot of sense. But for our APIs, we're going to have to design these ourselves to kind of control the access and the route or the endpoint to

particular resources. So when we look at

particular resources. So when we look at the project that we're going to build here where we're sharing, you know, videos or photos, we might have an endpoint that is, you know, our Aapi.com/photo,

Aapi.com/photo, right? And then we can access a

right? And then we can access a particular photo. You'll see what I mean

particular photo. You'll see what I mean in a second, but let's keep going. Now,

the next point is the query parameter.

Now, the query parameter is some extra bit of information that is typically used to filter the page or to get some more specific type of data. It always

will come after a question mark. You'll

see some kind of path or endpoint, a question mark and then one or multiple query parameters. In this case, we have

query parameters. In this case, we have a parameter video equal to 1 2 3. Okay.

And then if we come here, we have UTM source is equal to YouTube and page is equal to two. So we have two parameters and you can have as many parameters as you like. You just have to have these

you like. You just have to have these amperands that separates them. Okay? So

just understand that these are the core components of a URL and an endpoint. Now

let's keep going here and talk about the request and the response structure. So

whenever we visit some type of website, we refer to that website as the client or the front end. Okay, so us as a user, we go to our computer, we type, you

know, some website.

Okay, and then we are now on the client or the front end. Okay. And the front end is this kind of visual interface that we're able to interact with, that we're able to use. In the case of our post application or our photo

application, we can see the different post, right? We can make a post, we can

post, right? We can make a post, we can sign in, we can sign out. Now, the way that that actually works behind the scenes is that this user interface is communicating with some type of API. API

stands for application programming interface. The API you can essentially

interface. The API you can essentially see as kind of a secure layer. it's

running on a different device, some kind of server, so some computer essentially sitting in some location and it's facilitating all of the access to our data. So if we want to sign into our

data. So if we want to sign into our account, we send a request from the front end or the client to this API and this API returns some response. Okay,

this is the flow that I'm trying to get you to understand. You go to some website, you do something. If this thing involves some access to data, right?

Especially if it's maybe some confidential data or something, what needs to happen is a request will be sent to some backend, this kind of secure location. It will essentially

secure location. It will essentially check can this user do the thing that they want to do and then if they can, it will send this response back doing that thing. For example, deleting a post. We

thing. For example, deleting a post. We

would send a request to the backend. The

backend would say, "Okay, yep, you know, I'm going to be able to delete this post." And then it would return the

post." And then it would return the response saying, "Hey, this post was deleted. I want to upload a photo. I

deleted. I want to upload a photo. I

send a request to my backend. I say, I want to upload some photo. It returns

some response and says, "Yes, your photo was uploaded successfully." So, all of the heavy lifting, all of the secure operations, everything related to data essentially takes place on this backend or this API. And that's what I'm going

to be showing you how to build in this video. Now, when we send a request, so

video. Now, when we send a request, so we have this front end, right? This

client, it sends some data to the back end. And the main parts of a request are

end. And the main parts of a request are the following. Okay, we have a type of

the following. Okay, we have a type of the request which we're going to talk about in a minute or the method. We have

a path. The path is what we looked at here, right? So this path or this

here, right? So this path or this endpoint and oops, I didn't mean to save that. And we have a body. This is

that. And we have a body. This is

optional, but this includes additional data that we want to send along with the request. So for example, like the image

request. So for example, like the image that we want to upload or the caption or the name of the post or something like that. And then we have headers. This is

that. And then we have headers. This is

typically other additional information that has to do with things like authentication. So in the header of our

authentication. So in the header of our request, we would include something that indicates that we are, you know, this user. Okay, we are signed in as, you

user. Okay, we are signed in as, you know, Tim attechwithtim.net. The header

would kind of indicate that when we send that to the back end. I know this seems a little bit vague. Just bear with me.

We're going to make all of this crystal uh clear, sorry, when we actually get into the API example. We then have the response. Okay, so the request is the

response. Okay, so the request is the thing that we send from the front end to the back end essentially saying hey we want to do something and the response is what comes back from the back end to our

front end or to our client. Remember the

front end is the thing that you as the user actually see and then the backend is the thing that we as a developer typically write that facilitates all of the communication and the data. So from

the response we include a status code.

You may have seen something like you know 404 before which means not found.

That's an example of a status code. So

our backend will send a status code to the front end indicating what happened with the request. Common status codes are something like 200 for example, which means successful. I'm going to

show you a few more in a second and you get the idea. Then we have a body. Same

as we have the body in the request, we can send some additional data back to the front end that the front end might need. And then we have headers. Same

need. And then we have headers. Same

thing. headers will be related to typically security, authentication, the type of data, some weird things like that. If I scroll down here, I'm just

that. If I scroll down here, I'm just going to show you a few status codes and a few of the request types which are important to understand. Actually, let's

start with the request types. So, here

is an example of a very simple API. This

is a books API and this is the /books route or path or endpoint or whatever you want to call it. Now, you can see that we have something called a get endpoint. What this means is that we are

endpoint. What this means is that we are retrieving some data from this resource essentially from /books. We then have delete. This is the type of method you

delete. This is the type of method you would use when you want to delete something. We have post. This is the

something. We have post. This is the type of method you use when you want to create something. And you have put. This

create something. And you have put. This

is the type of uh method you would use when you want to update something. So

remember how I mentioned when we send a request, we specify some type or some method and that indicates what the front end wants to do. So, if the front end wants to get some data about some books,

it sends a get request. If it wants to delete a book, it sends a delete request. If it wants to create a new

request. If it wants to create a new book, it sends a post request. And you

can send all of these requests to the same route or the same endpoint. Okay?

And based on the type of the request, you can do something different. So, I

hope that makes sense. But these are the common methods or types of requests that you can send. Then we go over to HTTP status codes. Now, you don't need to

status codes. Now, you don't need to memorize all of this, but these are just some examples of status codes that you may see. So, you send this request,

may see. So, you send this request, right? You say, "Hey, I want to get a

right? You say, "Hey, I want to get a book, for example." All right? Then,

what the uh back end or the API is going to do is it's going to retrieve that data for you. It's going to send it to you and along with that, it's going to give you a status code. So, for example, it may say 200, which means okay. May

say 2011 because it created something.

You know, you get all these different ones like these redirection. You have

errors like bad request, unauthorized, payment required, a bunch of stuff that you can look at. You know, internal server error. Don't need to memorize

server error. Don't need to memorize them. I'm just showing you that there's

them. I'm just showing you that there's a bunch of status codes that are commonly used in web development. Okay.

Now, let's just have a look at an example request and response. And I

promise we'll get into the API. And

again, this will all crystallize, but this is just going to really help you understand how we design the APIs. Okay,

so user wants to update a post that they made. So, the type is patch. This is

made. So, the type is patch. This is

actually the exact same thing as put. So

if you ever see patch, it's the same as put, which just means you want to update something. If I wanted to create

something. If I wanted to create something, I would use post, right? But

I don't want to do that. I want to update. So I'm using patch. Okay, so the

update. So I'm using patch. Okay, so the type or the method of my request is patch. The path is / API/post.

patch. The path is / API/post.

And then this is the ID of the post. So

I'm saying, okay, I want to go to my API. I want to modify a post. This is

API. I want to modify a post. This is

the ID of the post that I want to modify. And then the body would be this.

modify. And then the body would be this.

This is the data that I'm actually sending where I'm saying, hey, this is the updated title. And this is the new caption that I want to use or the description or whatever for my post.

Then the headers includes this. This is

essentially my authorization token indicating, hey, I'm authorized to be able to perform this operation because of this thing right here, which we'll talk about later on. So we take all of

this, we send this to our backend and then this is the request, okay, that we create. Now from the backend we get a

create. Now from the backend we get a response back. So we send a request, we

response back. So we send a request, we get a response back and the response looks like this. We have status code 204 which stands for updated and then we have some body and this body says hey this is the title, this is the

description, this is the post ID, this is when it was updated, this is when it was created and it gives us that information back to the front end so we can display it to the user. We then have some headers and in this case we say hey

the type of you know data that we're returning back here is application/json which is essentially just the format of this data which we can talk about later.

Okay I know that's a lot of information but that is the kind of flow of an API and hopefully this is going to help us understand how we create APIs in a minute when we start coding them out.

Now last thing that we'll talk about a little bit later I'll just quickly show it to you is the authentication. So,

when it comes to using an authenticated API, um it's a little bit more complex than simply sending requests and getting responses. Essentially, what you need to

responses. Essentially, what you need to do is get something called a JWT token.

This JWT token looks something like this where you send this along with every single request to indicate, hey, I'm authorized to perform this type of operation. Essentially, you're

operation. Essentially, you're identifying yourself and what user you are so that the API knows you can do this thing or you can't do this thing.

You'll we'll look at that later. I don't

want to confuse you at this point. But

that is kind of the primer on web app development and APIs. Again, think of an API as essentially this kind of back-end server that sits there that facilitates

all of the operations that have to deal with data. Creating, reading, updating,

with data. Creating, reading, updating, deleting data. That's effectively what

deleting data. That's effectively what an API almost always deals with. And

it's doing that so it can do it in a secure way and then return data to some front end where the user can view it, display it, you know, mess with it, etc. So with that said, let's get onto the computer and let's start actually

writing some code in fast API. All

right, so I'm inside of my code editor here and for this video I'm going to be using PyCharm. Now you can use any code

using PyCharm. Now you can use any code editor or IDE that you want, but I typically do recommend PyCharm, especially for Python projects because, well, it is PyCharm and it supports Python the best. In fact, I do actually

have a long-term partnership with PyCharm. So, if you want to use it for

PyCharm. So, if you want to use it for free, you can click the link in the description, try it out, and see if you like it. It definitely is a great

like it. It definitely is a great editor, and again, what I recommend for pretty much any heavy Python projects.

Okay, so what I've done inside of PyCharm is I've just opened up a new folder. You can see I've got a folder

folder. You can see I've got a folder here called fast API tutorial. The way I did that is I essentially just went to open and I just opened a folder on my desktop. Okay? And you can again use any

desktop. Okay? And you can again use any editor that you want. Um, just make sure you open a folder. Now, from here, what I'm going to do is I'm going to open up my terminal and I'm going to start setting up my fast API project. Now, in

order to do that in Python, you need to use something called a package manager.

There's two notable package managers in Python. The first is pip. The second is

Python. The first is pip. The second is UV. Now, I'm going to suggest that you

UV. Now, I'm going to suggest that you use UV because this is significantly more modern and it just works a lot better. Uh, but if you don't want to use

better. Uh, but if you don't want to use UV, you can replace the commands I'm going to show you with pip. Okay, so UV is something that you need to install.

If you don't have it installed, I will leave a video on screen that explains how to do so. But once you have UV installed on your computer, what you can do from this open folder is you can type

UV innit and then dot. What this is going to do is create a new UV project for you where you're able to isolate all of the dependencies for this particular

project in this kind of one folder.

Okay, so we're going to type uvanit dot.

What that's going to do for you is it's going to create a few files inside of your folder. You're going to see a

your folder. You're going to see a main.py file, a piprotoml, and a few

main.py file, a piprotoml, and a few other files that you don't really need to worry about too much. Now, this

piprotoml file is going to include all of the dependencies for your project.

And it's what we're going to start modifying now by installing some different dependencies that we need for this project. So, if you want to work

this project. So, if you want to work with fast API, in order to do that, you need to install it. So, what we're going to do is we're going to type uvad and then we're going to start by just adding

fast API. Okay? So, we're going to type

fast API. Okay? So, we're going to type uvad fast api. When we do that, if we go back into pi project autotoml, you'll see this dependency has automatically been added for us. Okay, now that we

have it installed, we'll be able to actually use it inside of our Python code. Now, as well as fast API, what

code. Now, as well as fast API, what we're going to do is we're going to type uvad and we're going to install python-env.

Now, this is something that we need to use to manage environment variables because in a minute we're going to have some environment variables for handling our images and videos. So, we're going to go ahead and install this. Now,

there's a few other things that we need to install as well, so just bear with me. We're going to type uvad and we're

me. We're going to type uvad and we're going to install fast API- users and then inside of square brackets, we're going to type SQL

alchemy like this. Okay, so make sure it's spelled exactly like this. UV add

fast API- users SQL alchemy. This is

what we're going to use when we start handling the authentication and the authorization later on in our project.

So, we're going to go ahead and press enter. And then same thing, it should

enter. And then same thing, it should get added to our dependencies. Okay,

there's a few other ones that we're going to need here. So, we're going to type UV add and then we're going to add the image kit. So, we're going to say image kit like this. Uh, and sorry, it's going to be image kit io. Now, this is

the package we're going to use to handle our images and videos again, which we'll look at later on. We're also going to say uv and we're going to add uvicorn

and then standard. Unicorn is a web server in Python that allows us to serve our fast API application. You'll see how that works in one minute. So, we're

going to add Unicorn. And I promise we are almost done. Just a few more that we need to add. And then, sorry, we're going to add one more here, which is going to be a io sq light. Like that.

We're going to use this for interacting with our database. We may potentially need some more later, but for now, I think this should be fine. And that

should handle all the dependencies that we need for this project. Okay. Okay, so

we're going to close that and we're just going to quickly go here and make a new environment variable file. Now to do that, we're going to go new file and we're going to call this file env. This

is the file that you create when you want to store sensitive credentials, tokens or keys that your application is going to rely on. In our case, we need to access a key for image kit which is

going to allow us to handle the image and video uploads which I want to do now. Okay, so inside of this file, there

now. Okay, so inside of this file, there are three variables that we need to define. The first is going to be

define. The first is going to be imagekit_private_key.

All right. The next is going to be the imagekit_public_key.

And then the last is going to be the imagekit URL. Okay. So, we're going to

imagekit URL. Okay. So, we're going to put equal signs for all of these. And

we're just going to quickly grab these three values. So, we don't need to come

three values. So, we don't need to come back to this until much later in the video. Now, you may be wondering, what

video. Now, you may be wondering, what the heck are we doing, Tim? We haven't

even started writing the API. I promise

we're going to get there. I just want to get through everything, do all of the setup, and make sure that it's all ready to go. So we can just focus on coding

to go. So we can just focus on coding and I'm not moving around too much.

Right now what we're doing is we're creating this essentially kind of secret environment variable file. This is

something that's going to hold some values that we need for uploading the images and videos. Like I mentioned, we're going to use image kit to do this.

So what I need to do is get some keys and values from ImageKit. So I'm quickly just going to open up the ImageKit website. I'm going to leave a link to

website. I'm going to leave a link to this in the description. What we're

going to do is we're just going to make a new account on here. Again, it is free to use this. You do not need to pay for it. And essentially what this does is

it. And essentially what this does is give you all kinds of amazing tools for handling your images and videos, which is typically a huge pain, but they have all kinds of things like image and video optimization, formatting, cropping. It's

very interesting. So anyways, what we're going to do is make a new account. I've

already just made a new one. So again,

I'll leave that link in the description.

And from here, what we're going to do is go on to the developer options. From

developer options, we're going to look for our public key, our private key, uh, and then we're going to get our URL, which is up here. So, I'm going to copy my public key and then I'm going to put my public key right here. I then am

going to copy my private key, which is something that you do not want to share with other people. And before it will allow you to do this, you need do need to set a password for your account. So,

if you press this, I'm just going to blur my email, but I'll press the profile page and I'll just quickly set a password. Okay, now the password is set.

password. Okay, now the password is set.

So, we'll go back to developer options.

We'll go private key and I'm just going to copy this after I use my password.

So, let's use that and copy this. Okay,

so now that I've copied it, I'm going to go back to PyCharm. I'm going to paste it. Again, don't share this with other

it. Again, don't share this with other people. I will delete it afterwards. And

people. I will delete it afterwards. And

then lastly, we're going to grab this URL endpoint. Okay, which should be

URL endpoint. Okay, which should be right up here. And we're going to paste this inside. And now we have the keys

this inside. And now we have the keys that we need. Okay, so we're going to close the environment variable file. And

now what we're going to do is start setting up kind of the scaffolding for our project. So I'm going to make a new

our project. So I'm going to make a new folder. And this folder is going to be

folder. And this folder is going to be called src. This is typically best

called src. This is typically best practice when you're writing a fast API application. you create this source or

application. you create this source or actually let's change it to be an app directory where you actually have all of the code for your application and then you have this main py file which is kind

of what triggers the application to run.

So what we're going to do inside of this app folder is we're going to make a new file and we're going to call this app.

py and this is where we're going to start actually writing our fast API app and start getting into some Python code.

All right, so let's start writing a API.

We've gotten to the point where everything is set up. what we're going to do from this uh file right here. So

from here we're going to type from fast API import fast API with this capitalization and we're going to say app is equal to fast API with a set of

parenthesis. Now this is the fast API

parenthesis. Now this is the fast API application that we just created. And

what we'll need to do now is start setting up the different paths or endpoints that we want to have accessible on our API. Now remember for our API, we're setting this up essentially to handle data, to be able

to accept some type of request from our front end or our client and to return some type of data. So we can create data, delete data, read data, update data, right? We need to decide because

data, right? We need to decide because we're designing this API. So I'm going to start by just writing some simple dummy endpoints just to test and see how this works. Then we'll get into

this works. Then we'll get into endpoints that actually make more sense.

So the way that you make an endpoint in fast API is you type app which is the name of this variable right here that we defined dot and then you specify the

method for this particular endpoint. So

it can be get, post, put, delete depending on what you want this to do.

Now the most basic type which is common is to use app.get.

Now when you do this what you're going to do is you're going to specify the endpoint. So we're going to say slash

endpoint. So we're going to say slash and then something like you know hello dashworld. Okay, so this is the path or

dashworld. Okay, so this is the path or the endpoint. Now, I also forgot I need

the endpoint. Now, I also forgot I need to put an at symbol here because this needs to be a decorator in fast API. A

decorator is something with the at before it. And what you do beneath this

before it. And what you do beneath this is you define a function. The function

should typically be named something similar to this endpoint or path, but it doesn't need to be. You put a set of parenthesis, and then inside of here, you can return some data. So, let's just

quickly return the autocompleted data where it says message hello world. Okay,

so we have atapp.get/hello

world. What we're saying is, hey, when you go to our API and you go to /hello world, this function is going to be called and then we're going to return this data. Now, the data that we always

this data. Now, the data that we always return from our endpoints is either going to be a paidantic object, which we'll talk about later. I know that might not make a lot of sense, or it's going to be a Python dictionary. The

Python dictionary looks like this, right? You have some key associated with

right? You have some key associated with some value. And the reason why we return

some value. And the reason why we return Python dictionaries is because when we create APIs, we work with something called JSON. Now, JSON stands for

called JSON. Now, JSON stands for JavaScript object notation. It is the format essentially for dealing with data across the web. And you can essentially

think of JSON the exact same as you would think as a Python dictionary.

Okay, it's not exactly the same. There's

a few minor differences, but in our case, we can assume that anything that is a valid Python dictionary will be a valid JSON object. Again, keep in mind there's some caveats there, but generally that is the case, especially

with simple data. Okay, so now we've got this application, right? We've defined

this endpoint, but what we need to do is run it. Now, there's many different ways

run it. Now, there's many different ways to run the API, but the way that I'm going to suggest we do it is by going into this main.py py file here, deleting everything inside of here, and then

importing this app file and running it using something called Unicorn. So, what

we're going to do is we're going to say import uicorn like this. We're then

going to say if_ame is equal to_main then we're going to say unicorn.run.

We're going to put app colon app. I know this seems weird. I'll

colon app. I know this seems weird. I'll

explain what it is in one second. We're

going to say host is equal to 0.0.0.0 and we're going to say the port uh is equal to 8,000 and we're going to say reload is equal to true. Okay. Now, what

are we doing here? Well, first what we're saying is all right, I want to use this web server called Uicorn, which we've already installed, right, with UV, and I want to run a web server. Now, for

the web server, I want to run an API on it. the API that I want to run is

it. the API that I want to run is app.app. So that's inside of app. So the

app.app. So that's inside of app. So the

app folder here, the app file and then I want to run the API which is inside of the variable app. So let's say I were to change this and I called this hi. Okay,

then I would change this to be hi. All

right, so just keep that in mind. That's

how I'm getting these variables essentially. So we have the name of the

essentially. So we have the name of the folder is app, right? The name of the Python application is app and then this here is app and we have app.app.

Probably should have picked a better name for that, but it's okay. Hopefully,

you get the idea. Now, when I say host, this is specifying the domain essentially that I want to run this server on. Because we're running this

server on. Because we're running this locally on our own computer, when I specify 0.0.0.0, that just means run it on any available domain. So, it's going to run on what's

domain. So, it's going to run on what's called local host, which is just our own host, so only we can access it. as well

as our private IP address, meaning anyone else on the network would be able to access this as well if they knew the private IP address of this machine. Now,

there is ways to run this publicly, so anyone can access it. Not going to get into that in this video, but essentially the way that you're going to be able to access this application is you're going to go to whatever the IP address of this machine is. If we're on the same

machine is. If we're on the same machine, it's going to be localhost.

We're going to go to port 8000, and then we can access this resource right here, which is /hello-orld.

So for this what we can do is run this main.py file. To do that we simply type

main.py file. To do that we simply type uv run main.py.

Go ahead and press enter. And it says that there's some issue. This is because I'm currently running this app on another um uh what is it? Editor. So let

me just shut the other app down and rerun it. And then we should be good to

rerun it. And then we should be good to go. You can see that it's running now.

go. You can see that it's running now.

Again that issue you wouldn't have run into. It's cuz I had a demo application

into. It's cuz I had a demo application running in a different um editor that I have open. You'll see what's happened

have open. You'll see what's happened here is it now says Unicorn running on and then it shows you the URL or the domain where this is running right and then it kind of goes through this thing saying hey you know started the reloader

process and by me specifying reload equals true anytime I save or make a change to this file like if I do something I don't know hello here and then I save this you'll notice that the

file or sorry the server will shut down and restart with the changes that I made. So, it's really useful for when

made. So, it's really useful for when we're debugging and building something because it just shuts down and restarts anytime you make a change. Now, if I want to actually be able to view my application, what I can do is go to this

URL. So, you can just click it and open

URL. So, you can just click it and open it up. Now, it's saying this 0.0.0 isn't

it up. Now, it's saying this 0.0.0 isn't working. So, what we can do is change

working. So, what we can do is change this to be 127.0.0.1 or localhost port 8000. And when we do that, it should give us this uh thing

here saying detail not found. That is

totally fine. That's exactly exactly what we're expecting. Okay, so our API is now running and it's time to talk about the coolest feature of fast API, which is the docs endpoint. So here,

what you can do whenever you have a fast API application is you can go to /doccks. Okay, when you do that, it's

/doccks. Okay, when you do that, it's going to bring you to a page that looks like this, which actually specifies all of the endpoints and the configuration that you've set up for your API. So from

here, if I open this up, we'll be able to actually test out our API by pressing this try out button. This is going to send a sample request to this endpoint and then tell us what the response would

have been. So what I can do is press try

have been. So what I can do is press try it out. I can press execute and then you

it out. I can press execute and then you see what it does is it sends a request to this URL and then it tells me that I got this as my response saying message hello world and then it also told me the

code of this was 200 which means success. Okay, 200 successful response.

success. Okay, 200 successful response.

So there you go. We just sent a request, right? We tested it out. It's all

right? We tested it out. It's all

working. This is the thing I love about Fast API is that you can actually do this. You can directly go here and test

this. You can directly go here and test out all of your endpoints by simply going to the slashdocs endpoint. This

will become more useful later on, but always check this out. It's very, very useful. Now, there's also another

useful. Now, there's also another endpoint uh called /redoc.

This is kind of a newer version of that docs endpoint. It works the exact same

docs endpoint. It works the exact same way. We can test this out if we want um

way. We can test this out if we want um you know test the API etc etc uh and kind of see how this works. I am not going to uh dive into this too much right now but the point is there's this other endpoint called redoc which you

should be aware of but the one that I prefer to use is called /doccks. Now

just another quick thing if we wanted to we also could just directly go to slashhello-world.

If we do that you see it will give us message hello world because we set up a get endpoint and by default whenever you go to a URL in your browser you send what's called a get request right and

because we sent the get request we got the response back and the browser is able to actually render it and show it for us. But generally for all of the

for us. But generally for all of the other endpoint requests we're going to be looking at, we're going to have to use this /docs page or another tool to test the API. So we've now written kind

of this dummy get endpoint. However, it

doesn't really help us accomplish our project goal, right, of creating, you know, posts. So what I want to do now is

know, posts. So what I want to do now is I want to start adjusting the endpoint to actually make sense to our project.

It will change over time, but we're going to slowly kind of build towards what's called a CRUD application where we have create, read, update, and delete functionality. So, what I'm going to do

functionality. So, what I'm going to do is I'm going to delete this and I'm going to start setting up some stuff for handling posts. So, what I want to do is

handling posts. So, what I want to do is I want to set up my application so I can essentially retrieve and create new user posts. For now, we're going to start

posts. For now, we're going to start with text posts, but then later we'll get into the images. So, I'm going to make a new dictionary and I'm going to call this my text posts is equal to and we're just going to have an empty

dictionary like this. Okay. Now, what

we're going to do is we're going to make an endpoint and we're going to say at app.get get and this is going to be

app.get get and this is going to be slash posts. Okay. And for the function,

slash posts. Okay. And for the function, we're going to say define get all posts like that. Now, what this is going to do

like that. Now, what this is going to do is just return all of the posts that we have. So, we're simply just going to

have. So, we're simply just going to return text post like that. Super

simple. If we go back here now to this and we refresh, you'll see that we have uh why is it still showing that? Okay,

let me just restart my server because for some reason sometimes this messes up. So, we'll just restart it. Okay. And

up. So, we'll just restart it. Okay. And

I don't know what was going on there. I

had some weird issue. But anyways, I got this now back to the docs page. And you

can see we now have slashposts. And if I just try this out and execute, you see it just gives me an empty response.

Okay. That's what we're expecting because currently we don't have any posts. However, if we put a post in

posts. However, if we put a post in here, then we would be able to retrieve it. So, that's a good endpoint. But what

it. So, that's a good endpoint. But what

I'm going to do now is I'm going to start making some posts. So, I'm going to have some ID like one. Okay. And I'm

going to have this associated, if I can type properly, with some post. So for my post, I'm going to have another dictionary. I'm going to have title, you

dictionary. I'm going to have title, you know, new post and content, you know, cool test post.

Okay. And now I want to make an endpoint that allows me to retrieve one individual post. So first of all, let's

individual post. So first of all, let's just go back actually and let's quickly test and go refresh. Okay. And let's try this out and execute. And you can see that we get the one post showing up. But

maybe I want to be able to kind of filter and get just an individual post.

So I'm going to make a new endpoint. I'm

going to say at app.get and I'm going to type /post slash and then inside of parenthesis I'm going to type what's known as a path parameter. So this is a

dynamic value that we can actually change and adjust in order to get an individual post. So we're doing ID,

individual post. So we're doing ID, right? And then what I'm going to do

right? And then what I'm going to do here is say define get_ost and I'm going to say ID is of type int.

Now what this is doing is it's going to directly map this ID parameter to the ID value that I have inside of this path parameter inside of curly braces and

give it as a parameter to my function so I can use it inside of here. So now what I can do is I can say return text post

okay do get and then I can get id okay so now what I'm able to do is if I go here and I refresh we should see that we have another endpoint you can see it says get

post with an ID we can pass the ID so let's pass ID of one and we execute this um it's not giving us anything and I see the problem that is because ID is a

string when it should be a number. So if

we change this to a number now and we go refresh and then try out go with one and execute. You can see now that we get the

execute. You can see now that we get the individual post rather than a list of all of the posts. Okay. So just showing you this is how you create what's called a path parameter. Now if we want to

return an error here if the post doesn't exist, what I need to do is I need to import this HTTP exception. Now from

this function I can do something like if id not in text posts then I can raise an HTTP exception. I can specify a status

HTTP exception. I can specify a status code in this case something like 404 and I can say the detail post not found.

When I do that that's going to indicate okay we've had a 404 error you know not found and then post.found and that's how you can return an error. So now if we go back here and we refresh and we try to

access a post with ID like four or something and execute, you'll see that it says detail 404 and then it gave us a 404 error code. Okay, so what I just did quickly is I just had chatbt generate a

bunch of test posts because I'm going to use these um throughout the rest of this kind of section here to demo a few more things. All right, so what we've done is

things. All right, so what we've done is we've added a bunch of text posts. We've

added what's called a path parameter. We

had a normal kind of query endpoint here. And the next thing that I want to

here. And the next thing that I want to do is show you how we can use what's called query parameters inside of our functions. So up until this point it's

functions. So up until this point it's been pretty straightforward, right? We

just can call /ost. We can call for a particular ID. Now I want to make it

particular ID. Now I want to make it work so that we can do some kind of more advanced filtering using query parameters and then we'll continue from there. So I'm actually going to go

there. So I'm actually going to go inside of this function right here and I'm going to start adding some optional query parameters that we can pass to this that will allow us to kind of filter some of the content. So a query parameter remember is the thing that

comes after the question mark. So

something like maybe you know length equals 10 or something right whatever.

Um so that we can actually filter kind of the number of posts maybe that we're receiving. So what I'm going to do is

receiving. So what I'm going to do is I'm going to add a query parameter called limit. I'm going to say limit

called limit. I'm going to say limit colon int is equal to and by default it's going to be none. Now what I've just done is I've just specified that I now have the ability to pass a query

parameter called limit to this post endpoint. And I can then check if this

endpoint. And I can then check if this query parameter exists. If it does, I can use it. If it doesn't, I don't have to. So my idea with the limit parameter

to. So my idea with the limit parameter is that maybe I don't want to receive all 10 posts. Maybe I only want to receive the first three. Well, I can specify that with the limit. So let me show you how this works. I can do

something like if limit, then what I'm going to do is say return text post up to the limit. Okay, now this is not bulletproof because if the limit is larger than the number of posts, that will give us an error. But for now,

that's fine. and we'll just use that and

that's fine. and we'll just use that and then otherwise we'll just return the text post. So now if I go back to my

text post. So now if I go back to my page here and I refresh you're going to see that if I look at post we have the ability to add this limit query parameter. So what I can do is go try it

parameter. So what I can do is go try it out for limit I can pass maybe three for example and then execute and what it gave us an error. Okay that's weird. So

the reason we got that error sorry is because uh we're trying to apply a list operation on a dictionary. There's

multiple ways we can fix this, but for now, what I'm going to do just to make it easy is I'm going to say list of text posts dot and this is going to be uh

values like that. So, we'll just convert the values into a list and then return them. So, let's go back here and let's

them. So, let's go back here and let's go refresh. And then we'll go here. You

go refresh. And then we'll go here. You

can see we have a limit again. Let's go

maybe five and execute. And now you see we get a list with five items. If we change this to three, we get only three items. And if we don't have any limit at all and we execute, we get all of the items showing up. Okay, so just showing

you that's how you add a query parameter. If you want to do that, you

parameter. If you want to do that, you simply specify it in the uh parameters here. You can make it optional, which

here. You can make it optional, which means you can have something like is equal to none or you can make it mandatory by removing this and now you have to pass the query parameter. If you

don't um then you could potentially get some errors inside of the function. You

can pass multiple parameters like maybe you know content length or something or whatever and then you can specify something like int can make it string.

The reason why you need to specify the type here is so that it can be auto documented and validated by fast API.

The way the fast API works is that it automatically validates all of the data input that's coming into the function and out of the function for you. So when

I specify that this is an int, if I try to send something other than an int to this function, it's actually going to raise an error for me, okay? Other than

a number. So this documentation is actually very very good inside of fast API. And that's why you use what's

API. And that's why you use what's called a Python type hint inside of the parameters and you specify like what does the function return, what does it accept so that it can be really well documented and it can have what's called

this data validation. Okay, so at this point we've looked at query parameters, we've looked at path parameters, we've looked at the get endpoint extensively.

Now I want to look at the post endpoint and creating new data. So what I'm going to do is type at app.post

and I'm going to do slashpost.

Okay. Now from here what I want to do is be able to create a post. So I'm going to make a function called create_ost.

what we're going to take for creating a post is actually something different than for getting a post. So, like I said in fast API, it has automatic data validation, which means it's going to

check the data that's being sent into the function to make sure it's accurate.

Now, up until this point, we looked at the query parameters and the path parameters, but there's another way that we can send data to our API, and it's by using something called the request body.

Okay, the body is kind of like more hidden information. It's not directly

hidden information. It's not directly inside of the URL. It's in the field called body. And the way that we accept

called body. And the way that we accept that type of data is by creating something called a schema in fast API.

So what I'm going to do is I'm going to make a new file here. And I'm going to call this schemas. py. Okay. Now inside

of here, what we're going to do is we're going to define the type of data that we want to accept in our various endpoints.

So in order to do this, we're going to say import or we're going to say sorry from piantic import the base model and we're going to

define a python class. So we're going to say class post create. Okay. And this is going to inherit from the base model.

And then we're going to specify in here the fields that we want to uh accept essentially for a post. So for a post we're going to accept a title and we're going to accept some content. Okay, so

we have title and content for our post.

Now, the way that this works is that you inherit from this base model, which is kind of this special object in Python that has some special features. And what

we're able to do now is use this as a type to kind of receive body data inside of our functions. Again, I know it seems a little bit confusing. This is referred to as something called a schema. Very

common inside of fast API to use this and it's common that you put it in a separate file called schemas. So from

app.py, Pi we're going to say from app do schemas import and then we're going to import the schema that we just wrote which is the postcreate schema. Okay.

Now what we can do is for our create post we can say post. So let's do this post colon post create. Now when we do this

because we're using a pidantic model by default fast API knows that we're receiving request body. Okay. So not

receiving the uh query parameter receiving the body. So now what we can do is we can use this post data directly inside of the function to create a new

post. So we can do something like let's

post. So we can do something like let's do the following. Um okay we're going to say text post and then max of text

post.keys plus one because we need to

post.keys plus one because we need to find what the next ID essentially should be. And then we're going to say is equal

be. And then we're going to say is equal to and we're not going to do post.dict.

What we're going to do is we're going to make a dictionary and we're going to say the title is post.title

and the content is post dot content.

Now, because in my schema I've defined that my title is a string and my content is a string, fast API will make sure that these are indeed strings before it allows me to call this function. If they

aren't strings, it's actually going to automatically raise an error for me and tell me that I have a bad request, which means when I try to access the title or access the content here, I know that they're going to be valid. So again,

fast API automatically validates the data that comes into the API based on the types that you set, which is extremely useful. So now we've created

extremely useful. So now we've created this post endpoint. It's just going to create this new post. But what we really should do is we should return the new post that was created. So to do that, actually, let's just do this. We can say

post is equal to like this or maybe just new post is equal to this and then we can say this is equal to new post and we can return the new post. So now we have

a post endpoint to create a new post. So

what we can do is we can save should automatically reload. So now if we come

automatically reload. So now if we come here and we go try it out and we change this to like you know cool post and new post or something and we go execute you

can see it gives us the data back. And

then if we go back to posts, uh looks like the limit is required this time. So

let's go like 12 and execute. And you

can see we get the new post and our cool test post is showing up. Awesome. So all

of that is working. We now know how to accept request body, right? So this

different type of data and to create data. Now to delete data, it would be

data. Now to delete data, it would be pretty straightforward. You go

pretty straightforward. You go app.delete

app.delete and then same thing and you would kind of continue along these lines. And

there's more stuff that you could do related to that. I'm not going to show that this second. and we'll show it more when we actually get into kind of the finalized project. All right, so we're

finalized project. All right, so we're almost going to move on to databases, but I just want to cover one or two small more things about fast API that you should be aware of. Now, the first is going to be the output type. So, when

we created the post here, right, we're just returning new post. And if we go back to our kind of documentation here, let's just go to /docs and have a look at it. You'll see that it doesn't show

at it. You'll see that it doesn't show us like what type of data is going to be returned. Okay, it gives us kind of an

returned. Okay, it gives us kind of an example, but this isn't exactly, you know, what we're looking for. It's not

the best documentation in the world. So,

what we can do to enhance the documentation and actually give us um some more validation in our code, which is better, is we can specify the type of data that's going to be returned from

these functions. So, for example, for my

these functions. So, for example, for my create post, I can actually put this arrow here, and I can specify that I'm going to be returning this postcreate type. Now that's going to look exactly

type. Now that's going to look exactly like this, right? So it's the same schema that we had here. Now if we wanted to return something else, we can do class post

return or post response for example can be the same thing but just so the name makes more sense. And then we can change this to post response. And we can import

this from here post response. So now

we're indicating okay whatever we're returning from this function is going to be of this type. Now what this is going to do if I go back to my documentation here and I refresh is it's now going to

indicate to us if we look here the type that's actually going to be returned to us. You can see it gives us the value

us. You can see it gives us the value here. Example value is going to have

here. Example value is going to have title and content being returned on the successful response because we've specified that type. Now what it also does is it means we can only return data

from this function. Now that is of this type. If I try to return something else

type. If I try to return something else like just a normal dictionary, if I were to actually execute this endpoint, it would give me an error and say, "Hey, this doesn't match this schema. There

must be some kind of problem." Okay, so it adds a layer of protection for us to make sure that we're only returning what we want to return. And actually, in fact, let me show that to you. If I

change this to like an empty dictionary and then I go to my front end and I refresh here and I just go like try it out and I execute, you'll see it actually gives me an error and it says, hey, you know, missing this data type.

We're missing title. We're missing

content, which we should have in the response. So, we need to go back to new

response. So, we need to go back to new post and then it'll work from now on.

Okay. So, if we want to type the rest of our data, we can do that as well. So,

for example, when we're getting a post, we should also say that this will be the post response. And then for getting all

post response. And then for getting all of the posts, uh we're not going to type this one right now because the response types are actually a little bit different even though it's not intended.

Anyways, you get the idea. You can do this, okay, which is another useful thing to do inside of fast API. And if

you wanted to have like a list of posts, you do something like list, okay, and then post response like that. Awesome.

So now that we have that, what I want to do is start connecting us to databases because right now you'll notice if I refresh this application, all of a sudden my data is going to disappear.

Only the data that I have written inside of my code will stay persistent. Now

that's because right now all of our data is just inside of a dictionary that's stored in memory. So when our code refreshes, it all gets cleared and kind of reinitialized with this new dictionary. Now that's not ideal. So

dictionary. Now that's not ideal. So

what we're going to start setting up is database connection. So, we're going to

database connection. So, we're going to go to our app folder and we're going to make a new file called db.py.

Now, inside of all of these Python API libraries, you typically have something called a OM. An OM stands for an object relational mapping and it's something that allows you to prevent writing SQL

code or NoSQL queries and instead to write Python like code to be able to define data, retrieve data, create data, etc. Okay. Now, the OM that we're going

etc. Okay. Now, the OM that we're going to use here is something called SQL Alchemy. Um, I believe we already

Alchemy. Um, I believe we already installed it. If we didn't, then we can

installed it. If we didn't, then we can install it again in a second. But the

point is this will allow us to really easily work with our data. So bear with me here because this is a little bit of code that we do need to set up. Not all

of it's going to make, you know, 100% sense right now, but I promise it will later on as we keep going. Okay, so

let's start with some of our imports. So

the first thing we're going to do is we're going to say from collections.ABC

import the async generator. We're then

going to say import uyu ID which is something we can use to generate a unique identifier. We're then going to

unique identifier. We're then going to say from SQL alchemy import create engine. We're then

going to say from SQL alchemy. Okay. And

this is not what I want. We're going to say import the column. So let's spell column correctly. We're going to import

column correctly. We're going to import string. We're going to import text,

string. We're going to import text, datetime, and foreign key, which we'll use later on. Uh, and did I spell foreign correctly? No, I did not. So,

foreign correctly? No, I did not. So,

let's spell foreign key correctly. Okay,

we're then going to say from SQL alchemy. Okay, this is going to be

alchemy. Okay, this is going to be dialects.

Let's spell that correctly. Postgres SQL

import UU ID. We're then going to say from SQL alchemy.exe ext.async

io import the async session and the async session maker as well as the create async uh engine. So let's bring in the async session maker. Again, I know this stuff

session maker. Again, I know this stuff seems confusing. It's just a little bit

seems confusing. It's just a little bit of setup and then you never need to do it again. And then we're going to bring

it again. And then we're going to bring in from sql alchemy.org import the declarative base, but this is actually going to be a little bit different. It's

going to be declarative base like that and the relationship. Okay. Now, by the way, all of this stuff I do not have memorized. You don't need to memorize

memorized. You don't need to memorize it. It's simply something that we need

it. It's simply something that we need to be able to set up the database. Once

the database is set up, then it's a lot easier for us to work with this. So,

what we're going to do is we're going to define a uh variable and we're going to say the database URL is equal to SQLite.

Okay, so SQLite plus a io sq light.

Okay, colon three slashes dot slash test. DB. Now, what this is going to do

test. DB. Now, what this is going to do is it's going to allow us to connect to a local database file on our own computer called test.db, which is in the current directory. And sorry, this needs

current directory. And sorry, this needs to be a plus here. So, let's fix that.

That we want to use SQLite plus AIOS SQLite, which is essentially an asynchronous version of SQLite, which is a really simple database that we can run locally. later. If you wanted to connect

locally. later. If you wanted to connect to a production database, you simply need to change this URL to a URL string for like a remote database or a different type of database and then everything in your code would stay

exactly the same. You would just work in a different database. Now, what we're about to do here is we're going to define what's called our data models and then we're going to create the database which will automatically create the data

models for us. Now, essentially the data models is the type of data that we want to store. And if you've ever worked with

to store. And if you've ever worked with databases before, you'll know that when you want to store data, you need to specify the structure of that data. At

least when you're working with a SQL database, which is what we're doing right here. So, we need to specify like,

right here. So, we need to specify like, okay, what do we want to store for a post, for example. Well, we need to know the user that posted it. We have to have an ID. We want to know maybe the caption

an ID. We want to know maybe the caption of the post, the URL of the file. That's

the kind of stuff that I'm talking about here. Okay. So, what we're going to do

here. Okay. So, what we're going to do is we're going to create the data model for storing a post. We're going to make it a little bit more complex now and we're going to start working towards actually being able to store videos and

photos for our API. So what we're going to do is we're going to say class post and this is going to inherit from the declarative base. Now this is important.

declarative base. Now this is important.

You need to inherit from the declarative base so that it knows uh that we are making this a data model and this is something that we're going to store in our database. Okay. Now we need to

our database. Okay. Now we need to specify the table name. So we're going to say underscore table named underscore underscore is equal to post for example.

And then we're going to start specifying all of the fields that we want to have or all of the columns that we want to have in our data model. So we're going to say ID is equal to column. And then

we're going to type UUID. We're going to say as_UID is equal to true. We're going to say primary key is equal to true. And we're

going to say the default is UUID. UUID4.

And let me just fix the spelling here.

Okay. Now let me quickly explain what we're doing here. Essentially what we're saying is we want to have this ID column. Now for every single uh entity

column. Now for every single uh entity that you have in a database, you need to have some ID. Now the ID is typically what's referred to as the primary key.

The primary key is something that must be unique. So in this case, every uni

be unique. So in this case, every uni that we're that sorry, every ID that we have needs to be unique. That's why

we've marked it as primary key. And

because we've specified this UU ID thing, what this means is that we're automatically going to generate a random unique ID for it every time we insert one into the database. So every time we create a new post, a new ID will

randomly be generated that is guaranteed to be unique, which is the primary key or the way that we will look up this entity. Okay. Now, the next thing that

entity. Okay. Now, the next thing that we're going to have is we're going to have a caption. The caption is going to be some column and this is going to be text. Now,

you'll notice that the way that we specify the data that we want to have is we say, okay, we're going to have some name, some field name, so like caption ID, we say it's going to be a column. If

we're storing data, if we're storing a relationship, we would set it to a relationship or a foreign key or something different. And then you

something different. And then you specify what you want in that column. In

this case, I want to store text, right?

So, I say, okay, caption, it's going to be text. Then I'm going to have a URL.

be text. Then I'm going to have a URL.

This is going to be the URL for the uh what do you call it? Photo or video. And

this is going to be column of string.

And we're going to say nullable is equal to false, which means this can't be null. It has to have a value. We're then

null. It has to have a value. We're then

going to say the file type is equal to column. Same thing, string nullable is

column. Same thing, string nullable is false. We're then going to have the file

false. We're then going to have the file name. It'll be the exact same thing. So

name. It'll be the exact same thing. So

string nullable equals false. We'll then

have a created at and we'll say column date time. And rather than nullable,

date time. And rather than nullable, we're just going to say default is equal to datetime dot UTC now. And then we're going to import datetime.

So we're going to import uh datetime like that. Not now. Import date time

like that. Not now. Import date time like that. And now this should work.

like that. And now this should work.

Okay. So that's all that we need for the post. Later we will adjust this slightly

post. Later we will adjust this slightly to link it to an individual user, but for now because we don't have users in our app, we're just going to have kind of a simple post. So the way that this will work now is that whenever we want to create a post, we'll need to pass a

caption, URL, file type, file name, and created at or actually create at will be automatically created for us. And then

we'll be able to make this new post and store it in our database. If we had other data models, we would define them inside of here or in other files and import them inside. But for now, this is how we're going to do it. So next, we

need to actually create the database. So

we're going to say our engine is equal to this create async engine with a database URL. We're then going to say

database URL. We're then going to say the async session_maker is equal to the async session maker and we're going to pass our engine and then

we're going to say expire on commit is equal to false. Don't worry too much about that. Essentially what we need to

about that. Essentially what we need to do right now is we need to create this database engine which can look at all of these models and automatically create the database for us. We're then going to

say async define create db tables. What this is going to do is

tables. What this is going to do is create the database for us as well as create the tables. So we're going to say async with engine.be.

Okay. And then this is going to be as connection. And what we're going to do

connection. And what we're going to do is say await con. Okay. The connection.

So run_sync and then we are going to say the declarative base. Okay, dot

declarative base. Okay, dot metadata.createall.

metadata.createall.

Now, what this is going to do is it's going to find all of the classes that inherit from the declarative base and it's going to create them inside of the database. That's all that it's doing.

database. That's all that it's doing.

We're then going to have another function. We're going to say async

function. We're going to say async define get async session. Okay, this is going to return

session. Okay, this is going to return an async generator with an async session and none. And then we're going to say

and none. And then we're going to say async with and I know this is confusing.

Bear with me. We're going to say the async session maker as session and we're going to yield the session. Okay, again

bear with me. This is actually almost done at this point. What we're doing is we're creating all the databases and the tables, right? What this does is it

tables, right? What this does is it starts the database engine and then it creates all the tables and creates the database. Then we have this get async

database. Then we have this get async session. What this is going to do is it

session. What this is going to do is it is going to get a session which will allow us to actually access the database and write and read from it asynchronously. Okay, so we're doing

asynchronously. Okay, so we're doing this using async. If you don't understand async in Python, don't worry too much about it. I will explain the the kind of important stuff later. So

that's all we need from this particular file. Later we will add a few other

file. Later we will add a few other things to store our users for the application, but for now this is fine.

Okay, so there we go. We've now written the database stuff. What we're going to do now is we're going to go into our app. py file and we're going to start

app. py file and we're going to start importing some of the things that we need so we can actually use the database. So we're going to say from app

database. So we're going to say from app db import the post the create dbn tables and the get async session. Okay. Now

what we need to do is we need to set something up so that as soon as the application runs we create the database automatically if it's not already created. Now, in order to do that,

created. Now, in order to do that, again, this is going to look a little bit complex. Don't worry, just set up

bit complex. Don't worry, just set up once and then you're good. We're going

to say from SQL Alchemy.exd.async.io

and then we're going to import the async session. Then we also need to import

session. Then we also need to import something called the async context manager. So, we're going to say from

manager. So, we're going to say from context lib, this is built into Python, import the async context manager. We're

then going to say at async context manager. and we're going to say async

manager. and we're going to say async define lifespan. We're going to take in

define lifespan. We're going to take in our app which is an instance of fast API. And what we're going to do is we're

API. And what we're going to do is we're going to say await and we're going to say create db and tables. And then we're going to yield. Don't worry too much about this. It's kind of advanced Python

about this. It's kind of advanced Python syntax you don't really need to understand. And then all we're going to

understand. And then all we're going to do here is when we say app is equal to fast API, we're going to say lifespan is equal to lifespan. What this is going to do is it's going to automatically run this function as soon as the app is

started. It's going to create the

started. It's going to create the database and the tables for us and just make sure that this is essentially handled correctly and cleanly exit once the when sorry the application stops.

Now these other imports we'll use later on. Uh for now we'll just leave them in.

on. Uh for now we'll just leave them in.

Okay. So now if we just want to do kind of a sample test here, we can shut down our server and rerun it and it should automatically create the database for us. However, it's giving me an issue

us. However, it's giving me an issue saying datetime.Uutc UTC isn't a

saying datetime.Uutc UTC isn't a function. Let me quickly fix that. So,

function. Let me quickly fix that. So,

we're have to actually change this to say from daytime import daytime. So,

just change that import here in the DB file. And now, if you come back here and

file. And now, if you come back here and we shut this down and we restart it and we got another error. Let me quickly fix that. Okay, so another silly error here.

that. Okay, so another silly error here.

We're going to go inside of our db.py

file. What we're going to do quickly is say class base and this is going to inherit from the declarative base. And

then we're just going to say pass. And

we're just going to change all instances of declarative base down here to say base. Kind of a silly error. Again, a

base. Kind of a silly error. Again, a

little bit complex. And then same thing when we go here, just change this to say base. And that should fix the problem

base. And that should fix the problem for us. Essentially, we just cannot

for us. Essentially, we just cannot directly inherit from declarative base.

Uh we need to do this kind of other base class first. A little bit weird, but

class first. A little bit weird, but that will allow us to set up the database. I know the database setup

database. I know the database setup seems a little bit confusing, but once it's set up again, you don't need to change it. So let me just shut this down

change it. So let me just shut this down and then restart it. Okay, so the server is running. We didn't get any errors.

is running. We didn't get any errors.

And the way we can test if this is working is if this test db file was created. It looks like it was for me,

created. It looks like it was for me, which means the database connection is set. And now we don't really need to

set. And now we don't really need to touch much in this database file. And we

can just start using the database to actually create new posts. So in fact, let's start doing that. Let's actually

scrap pretty much everything that we have so far. I know it seems like why do we get rid of it, but trust me, we're just going to write this in a better way now. And what we're going to do is we're

now. And what we're going to do is we're going to start writing the endpoints for uploading or creating a new post and doing the image and video upload. So, as

I mentioned, we're going to start doing the file upload. Now, to do that, we're going to have to import a few more things. And again, just bear with me.

things. And again, just bear with me.

I'm going to explain it step by step as we go through that. And then we'll start adding the users, a bunch of other stuff as well. So, what we're going to do is

as well. So, what we're going to do is from our fast API import at the top, actually, we're going to import file.

We're going to import upload file the uh what is it form and the depends.

Okay. Now we're going to make a new endpoint and we're going to say at app dot and this is going to be post because we're going to be uploading a file and this is going to be slashupload.

Now this is going to be to essentially make a new post. So when we make a new post, we're going to upload either a video or a photo and then some caption for that video or photo and then it will

be posted. So in order to do this, we're

be posted. So in order to do this, we're going to say async define upload file.

We're using async because we're going to have some async operations in here where we essentially wait for something to occur. Fast API is asynchronous by

occur. Fast API is asynchronous by default. So you can always use the async

default. So you can always use the async keyword for these functions. Now what

we're going to do is we're going to say file and this is going to be upload file is equal to file with three dots inside.

What this means is that we're going to be able to receive a file object to this endpoint. Okay. We're then going to say

endpoint. Okay. We're then going to say the caption is a string which is equal to some form data. So rather than actually just accepting a request body, we're going to accept something called

the request form. There's different

types of data you can send to the endpoint. For example, you can send a

endpoint. For example, you can send a file, you can send a form, you can send a request body, you can send query parameters. This is just another type.

parameters. This is just another type.

So, we're going to accept the caption from some form data. Okay. We're then

going to say our session is an async session, which is equal to depends, and this is going to be get async session. Now, this

is going to look a little bit weird, but in fast API, we have something called dependency injection. This is

dependency injection. This is essentially a dependency injection. and

it'll light up in a second here when we start using it where what's going to happen is we're automatically going to get the asynchronous session by calling this function and pass it as the

variable session inside of this function. This is how it works when you

function. This is how it works when you want to essentially trigger another function to run as a dependency for this function. So we're saying we want to get

function. So we're saying we want to get the asynchronous se session sorry for our database so we can use the database inside of this function. in order to use it in this function. That's how you do

it. You write this kind of dependency

it. You write this kind of dependency injection where you say this function depends on this right here. It will run the function. It will get the database

the function. It will get the database object. It will pass it to us and then

object. It will pass it to us and then we'll be able to use it directly inside of here. Okay. So now inside of here,

of here. Okay. So now inside of here, what we're going to do is we're going to take the file and we're going to upload it. That's going to take us a second to

it. That's going to take us a second to be able to do because we need to use image kit. So before I do that, I'm

image kit. So before I do that, I'm going to show you how we can create a new post with some kind of fake post data and then how we can do actually the upload for that. So to make a new post,

we can say post is equal to post and we can specify things like the caption is equal to the caption. We can say the URL

is equal to you know dummy URL and later we'll fill that in. We can say the file what is this file type is equal to for

now we can just go photo then we can do a comma and we can say the file name is equal to dummy name okay so let's go dummy url dummy name again there's a few

other things we can add later but for now this is fine now in order for us to actually add this to the database the way that we do that is we say session do add

okay and we simply add this post here that we created. Then we say await session.

So the way that you add something is you create a new post or create a new object of whatever it is that you want to create. You add this to the database

create. You add this to the database session and then you commit the session.

It's important that you commit this because committing it will actually save it. adding it to the session is like

it. adding it to the session is like staging it saying hey this is ready to be added but it won't actually fully be written into the database unless you commit the session. Now another thing

you can do after this is you can say wait session.refresh

wait session.refresh and you can refresh a particular object and what this will do now is it will go and look in the database and populate

any entries here that were automatically created when it was added to the database. So for example we have this

database. So for example we have this created at and this ID when we specify the post we didn't specify an ID or a created at that gets automatically

created when we commit this in the session. So when we refresh the post it

session. So when we refresh the post it essentially gets hydrated with that extra data where we now get the ID and the created at as a part of this post

which we can now return to our user. So

what we can do here is we can just say return and then we can return the post.

We don't need to do that but we can if we want, right? So we can say return post uh and then we will get that data.

So we can test this but before we're going to know if it was actually added to the database, we need to write an endpoint that's going to allow us to view the different posts. So we're going to say at app.get

and we're going to call this the feed.

So we're going to say slashfeed. We're

then going to say async define get feed.

And what we're going to do here is we're going to say the session, this is an async session is equal to depends on get async session. Now the reason we're

async session. Now the reason we're doing that is because we need to access the database here in order to get all of our posts. So we need to bring this in

our posts. So we need to bring this in as the dependency injection. Now quickly

I do need to import something. So I'm

going to say from SQL alchemy import select because this is going to allow us to select different posts. So now what we're going to do is we're going to say result is equal to await session. This

is our database.execute.

Okay. And this is how you can execute a query. And we're going to say select and

query. And we're going to say select and we want to select on the post um what do you call it object or post kind of table. And we want to say order_by.

table. And we want to say order_by.

And we're going to say post dot. Okay.

Like this created dot descending.

Okay, so querying here is a little bit weird, but what we're able to do is say, okay, I want to select posts, right? So,

I want to start looking through posts and then you can add these various filters like I want to order it by all of the posts that are created at and the descending, right? So, I want to go in

descending, right? So, I want to go in the order in which they were created.

Then I could also do something like, you know, dot filter, right? Or like all these other things. And you can filter by specific criteria. I'm not going to go through all of it, but essentially if you just look up like SQL, Alchemy, Fast

API online, you'll see all of the different ways that you can query different data. If you want to just get

different data. If you want to just get all of the posts and you don't care about doing any kind of filtering, you can just say select post. That will give all of them to you. Okay? And then if you want to check various fields or relationships, you can do that. We'll

look at that a little bit later on.

Okay. So now we have our result. This is

going to be all of our posts. Now what

we're going to do is say post is equal to and we're just going to go row okay zero for row in result doall.

Now what the resultall is going to do is just give us all of the results from this particular query. The reason why we're doing this is because I want to convert this into a list. Essentially we

need to step through all of the results and take them and pass them into this in order for us to actually access them all at once. It's due to the way that Fast

at once. It's due to the way that Fast API returns the results here. It returns

in what's called a cursor object where you're stepping through the database. So

what I'm doing is I'm looping through all of the values and then just pulling them into individual values that I store inside of here. Okay. Then what I'm going to do is I'm going to say my posts

data is equal to a list and I'm going to say for post in posts and I'm going to start creating kind of a more uh comprehensive post object that I can return to my front end. that's going to

include some data that we need about our post. So, we're going to say post

post. So, we're going to say post data.append.

data.append.

Okay. And then inside of here, we're going to have an object. For the object, we're going to say ID is equal to a string of the post do ID. So, I'm going to convert it from a UU ID object to a

string. I'm then going to say the

string. I'm then going to say the caption is the post.caption. I'm going to say the URL, if we can spell this correctly,

is the post dot URL. I'm going to say the file type is the post.file type. And

then I'm going to say the file name is the post.file name. And I'm going to say

the post.file name. And I'm going to say created at is the post.created atiso

format, which is going to give me a time stamp in a format I can actually read.

Then I'm simply going to go down here and I'm going to say return post and I'm just going to return all of my post data. Okay. Uh and that should

be post data like that. So that is going to complete this kind of get feed function which will give me all of my posts. This should allow me to create a

posts. This should allow me to create a post when I upload a file. Again, for

now the file um we haven't specified but we'll do that in a second. So now let's give it a test and see if this works.

So, let's rerun our backend. I'm just

going to shut this down and restart it.

Let's go here. Let's refresh. We see we have an upload and see it says multiart form data. So, I'm going to try it out.

form data. So, I'm going to try it out.

And now it allows me to choose a file.

So, let me pick some file here. Okay.

So, I just uploaded some files, some pay slips from a while ago. Let's go caption hello world. And let's execute. And

hello world. And let's execute. And

let's see what we get. And it gives us the response body. Okay. photo, dummy

URL, date, hello world, and the ID. So

now if we want to see if it's actually in the feed, what we can do is go to get feed, try it out, and execute. And you

can see that we get the post. I think I press this twice. So we get two posts showing up here, but it's reading those from the database. And the important thing is that if I were to shut this application down and restart it, these

would still be in the database because, well, they're here persistently, right?

And they're stored in this file. If we

want to delete them, we can just delete this database. Okay, so now we have the

this database. Okay, so now we have the ability to upload or create a new post and to kind of view the post. Now we

need to start actually handling the image and video upload. And to do that, we're going to use image kit. So what

we're going to do is make a new file here and we're going to call this image kit or not image kit, images.

py. Okay, so from here we're going to go images. py and we're going to start

images. py and we're going to start importing a few things. We're going to say fromv import load.env.

import load.env.

We're going to say from imagekit.

Okay, IO import if we can spell this image kit. And remember, we imported

image kit. And remember, we imported this or installed this at the beginning.

We're going to import OS. And then we're just going to call this load.env

function. We're then going to say image kit is equal to image kit. And we are going to essentially specify all of the variables that we defined here in ourv

file. So to do this, we're actually just

file. So to do this, we're actually just going to use this autocomplete. We're

going to say our private key is equal to os.get envage kit private key public key

os.get envage kit private key public key os.get env public key URL endpoint.

os.get env public key URL endpoint.

OS.get envage kit URL endpoint. Okay, so

the same variables that we have here.

And actually, let's just make sure they're spelled correctly because this one is a little bit different. So let's

fix this to just be imagekit URL. Okay.

Now, what are we doing here? Well, this

load.env env function will look for the presence of this enenv variable and essentially load it for us. Okay, so it will load these values in so we can now access them. Now to access those

access them. Now to access those variables we use this os.got get env function which will be able to find the presence of these environment variables and load them into our code. Very

important that we're doing this on the back end not on the front end. And I

want to explain to you how we now kind of upload content using image kit which was which is what we're about to do. So

let's go into app.py py and let's import image kit so that we can start using it.

So what we're going to do is say from app dot images import and we're going to import image kit and then we're going to say from and

this is going to be imagekit ioles.upload

ioles.upload file request options import the upload file request options because we're going to use this in a second to specify how we upload the file. Now before I start kind of diving into the code here, I want to go to the image kit

documentation and start kind of explaining to you how this works. All

right. So if you remember at the beginning of the video, we would have created an image kit account. The

account looks something like this where you have this dashboard. Now image kit can automatically host all of the images for us and it can handle uploading, deleting them, cropping them, modifying

them, and more importantly just being our storage. So we don't need to worry

our storage. So we don't need to worry about storing images and videos which can be a huge pain. Now, you do have the ability with image kit to connect this to external storage. So, for example, if you go to external storage here, you can

add a new one and you can can connect it to like an S3 bucket if you're familiar with what that is or other locations where you can essentially have image kit managing this external bucket. You don't

need to do that. Uh, but you can. In our

case, we're going to use image kit as our DAM. So, it's automatically going to

our DAM. So, it's automatically going to handle all of the asset management for us. Eventually, when we start uploading

us. Eventually, when we start uploading stuff, we'll see in our media library that it will show up here. We'll be able to click into the various files. We can

view them here. We can view the information. We can edit the tags, get

information. We can edit the tags, get embeds, URLs, all of this kind of stuff.

Just makes it very easy to manage the images. Now, in terms of using image

images. Now, in terms of using image kit, uh what we can do is use a single API. Funny enough, we're building an API

API. Funny enough, we're building an API and we're going to use an image kit API to upload the images. Once the images are uploaded, we can then just change some query parameters in the URL for the

image and we can specify the width, the height, if we want to add text on top of it, if we want it black or white, if we want to crop it, whatever. As you can kind of see, it's showing you right here, which makes this extremely useful.

It also has performance optimization, a lot of other features, but let's go into the docs. So, I'm going to go docs like

the docs. So, I'm going to go docs like this. Let's go to the Python

this. Let's go to the Python documentation. You can see it supports a

documentation. You can see it supports a ton of different frameworks. I'm going

to explain to you how we upload it. Now,

you can use this with a lot as you can see, JavaScript, React, Angular, all of this kind of stuff. In our case, we're doing this from Python. And so, because we're doing that, we imported or we

installed the image kit IO library and then we initialized it like this. Now,

we're going to be doing what's called a backend or server upload. So,

essentially, the user is going to send some image to our backend and then our backend is going to upload this to image kit. Now, it's important that we do it

kit. Now, it's important that we do it this way so that we can securely control what images we upload or which ones we don't and have them stored on our server. Whereas, if you were to upload

server. Whereas, if you were to upload this directly from a front end or a client like a JavaScript application or something, um, that's not as secure.

Okay? And you don't have as much control because you're essentially exposing different tokens for image kit on your front end, which you may not want to do.

So, it shows us right here some kind of code snippets of how you can do the upload. You have some URL to an image.

upload. You have some URL to an image.

In our case, it's going to be some data which I'll show you. And we can do imagekit.upload file. Pass the different

imagekit.upload file. Pass the different piece of information and then it just gets uploaded and it's going to return to us essentially an object that looks like this where we have the URL for the

image, the name, tags, all of this kind of stuff that we can then use and store.

Okay. And then if we want to generate a URL, we can do something like this.

Again, we're not going to talk too much about everything here, but that's kind of how we do the upload. Hopefully this

makes a little bit of sense, but the point is user will send a file to our API. Our API will then upload it to

API. Our API will then upload it to image kit. We'll grab the URL, save that

image kit. We'll grab the URL, save that in our database, and then serve that to our user on the front end. So, we're

going to go and we're going to import a few other things that we're going to need to perform this upload. So, what

I'm going to do is I'm going to say import sh util. I'm going to import OS.

I'm going to import UUID and I'm going to import temp file. Now the process is going to be that when the user sends us this file, we're going to create a temporary file which is a copy of this

file. We're then going to upload that

file. We're then going to upload that copy and then essentially remove or delete that copy from the machine because we'll no longer need it. So what

we're going to do is create a variable and we're going to say our temp file path is equal to none. We're then going to

say in a try block with okay temp file.named named temporary file. We're

file.named named temporary file. We're

going to say delete is equal to false.

And we're going to say the suffix is equal to os.pathsplit

text. And we're going to say this is going to be file.file

name. And then this is going to be at index one. Okay, this is a little bit

index one. Okay, this is a little bit weird. Again, just bear with me here.

weird. Again, just bear with me here.

We're going to say this is as temp file and we're going to say this is as temp file. What this is going to do is

file. What this is going to do is essentially make a named temporary file that ends in whatever the file name is that was uploaded here. Then inside of

here, since we have this temporary file, we're going to say the temp file path is equal to the temp file.name. And we're

going to say sh util.copy

file object. And this is going to be filefile and then the temporary file. And let me just correct myself here. What we're

doing is when we create this temporary file object, we're using or we're having the end of the temporary file have the same extension as the file that was uploaded here. So if they upload a JPEG,

uploaded here. So if they upload a JPEG, for example, we create a temporary JPEG.

If they upload a MP4, we create a temporary MP4. Okay? So what we do is we

temporary MP4. Okay? So what we do is we create the temporary file. We then copy the contents of this file into the temporary file. And then that kind of

temporary file. And then that kind of completes this width statement. Then

we're going to start doing the upload.

So we're going to say our upload result is equal to imagekit.upload_file.

What we're going to do is we're going to say file is equal to and we're going to open the temporary file path in this RB mode which stands for read bytes. We're

then going to say our file name is equal to file.file name. And we're going to

to file.file name. And we're going to say the options is equal to and this is going to be the upload file request options. And in here we're going to say

options. And in here we're going to say use unique file name. This is going to be equal to true. And we're going to say the tags is equal to and inside of a

list we're going to say backend upload.

So we know that we uploaded this from our API. Now this is all we need. Like

our API. Now this is all we need. Like

that's literally how easy it is to use image getet. We just write this one line

image getet. We just write this one line where we essentially open the file. We

upload it to image kit and then it's going to give us a result that contains all of the metadata that we need. So

we're going to say if upload result dot this is going to be response.http

status code is equal to 200. That means that this was successful. Then what we're going to do is all of this where we essentially create the post. Okay. Now

we just need to structure this a little bit better because it's a bit difficult to read. But we have this try block,

to read. But we have this try block, right? So, I'm just going to put an

right? So, I'm just going to put an except block here. So, we're going to say except exception as e. And then we can put a pass right here for now. And

then we're going to say finally. And in

the finally block, we're just going to make sure we clean up the temporary file. So, we're going to say if temp

file. So, we're going to say if temp file path okay or or sorry, not or and os.path.exist

os.path.exist

the temp file path. Then we're just going to say os.unlink.

And we're going to unlink the temporary file path. And then we're going to say

file path. And then we're going to say file.file.close.

file.file.close.

Okay. So, this is just going to clean up our file objects. So, at the end of this function, we're all good and everything's cleaned up. Okay. And then

for the exception, let's just quickly handle this. We're just going to say

handle this. We're just going to say raise HTTP exception status code 500.

And we'll just put whatever the string error was so that we're able to have a look at it. Okay. So, now at least the try accept block is done. And we just need to handle this part. So, what we're saying is all right, you know, we've now created the temporary file. We've

uploaded it. We're going to check the response and we're going to make sure that this was successful. Now, if it was successful, what we're going to do is we're going to create this post. But for

the URL this time, we're going to change it to be the upload result dot URL. For

the file type, we're going to say this is video if file.content content type dot

starts with video slash otherwise we're going to put the type as image and for the file name this is simply going to be

the upload result okay dot and this is name so now we're actually using the content from imagekit and we actually will have the URL for the image hopefully that makes sense but that's

pretty much what we need to do for the upload and I think that should actually be good. So, what we'll do now is let's

be good. So, what we'll do now is let's bring open our terminal again. Let's

just restart this and let's go back here and let's test this from our docs. Okay,

so let's go upload. All right, we're going to go try it out. We're going to put a file. So, we need to upload an image. So, let me just upload one of

image. So, let me just upload one of these images here. Let's go hello world and let's send this. and it says module NT path has no attribute split text.

Okay, so I need to remove one of the T's here. So it's split text in one word. So

here. So it's split text in one word. So

that was my problem there. Let's go back and refresh and just try this again. So

we're going to go try it out. Upload

again. Just upload an image or a video.

Needs to be some media. Say hello and then execute this. It's going to take a second because it does need to do the upload. And then we got some issues

upload. And then we got some issues saying nontime object has no attribute HTTP status code. So we probably just spelled something wrong. So let's go here and fix this. Yeah. So we have

upload result. This needs to be response

upload result. This needs to be response metadata.

Okay. So let's spell metadata correctly.

And now let's test it again. Apologies

guys. This is just a part of programming. Refresh.

programming. Refresh.

Try it out. Choose a file again. Some

media. Okay.

Hello world. And let's see. And here we go. We get the response body. And now

go. We get the response body. And now

what I want to check is the URL. So it

has a URL here. So let's copy this and let's paste this in our browser. And we

should see that we get the image now and it is uploaded. And importantly, if we go to the media library, we should be able to refresh here. And we should see that now the images appear happening

twice cuz we uploaded it twice even though we got an error the last time.

And you can see this shows up. And by

the way, this is Kenny, one of my co-founders from Dev Launch and someone that we were filming a testimonial video with. Anyways, that's kind of the random

with. Anyways, that's kind of the random image that you guys are seeing. Okay, so

it's working. We can see it's uploaded here in ImageKit. It's working now from the back end. What what I want to do next now is test out this feed endpoint and see if this gives me all of the content. So, let's execute. And you can

content. So, let's execute. And you can see there we go. So, we have this new post, right? We have the image kit URL.

post, right? We have the image kit URL.

And now I just want to talk about kind of the advantage of using image kit and what we can do with these URLs that is super cool, which I'm going to show you in one second. So, I'm going to grab one of these URLs, which I would recommend

that you do. I'm going to show you how we can modify modify it, sorry, by literally just changing some parameters in this URL. Okay. So, I have the URL in this one tab here. And then I also just

pulled up the image kit documentation.

And what you're able to see, let me just make this a little bit bigger, is that we can have these transformation parameters directly in the URL to modify the image. So, notice I have, you know,

the image. So, notice I have, you know, image kit demo. And then we can do these transformations of like the width and the height directly on this URL. Let me

show you and then I'm going to show you a bunch of other ones that we can do. So

what we do is we go in between the file name and the uh what do you call it? Um

project ID for image kit and we just put this in directly. And when we do that you see that I just modified the width and the height directly by cropping it by literally just putting those

parameters. If I put like 500, see now

parameters. If I put like 500, see now that it goes up. If I put width of like I don't know what is this 700. See, now

we get an image that looks a little bit more complete, right? And we can just add it directly like that. Now, we also can pass this as a query parameter if that's easier for us to do. And you can see it shows some examples of kind of

resizing the image. Now, if we go here to image transformations, you'll see there's just so many that we can do here, right? Like we have an AI

here, right? Like we have an AI transformation, which is currently in beta, which is kind of cool. We can add overlays directly on top of the image.

So we can have like some local image we want to put on top of this image and directly embed it. We can do effects and enchantment or enhancements, sorry. So

we can have like econtrast. So So let's actually copy this and see if we can get it. So we'll do TR and then H-300

it. So we'll do TR and then H-300 E contrast.

Okay. And make sure there's no space.

And then if we run that, you can see that it gives us some more contrast. We

can sharpen it. So if we want to pass eharpen, let's change that to e d-sharpen.

And you can see it now sharpens the image a little bit. It's a little bit difficult to see probably with my screen recording software, but it is doing that. And then we have video

that. And then we have video transformations. These are cool because

transformations. These are cool because we can have, for example, like thumbnails for videos. So if we upload a video, we can try to get a thumbnail from a specific portion of it. So for

example, we can use this ik thumbnail.jpeg. If we just put that at

thumbnail.jpeg. If we just put that at the end of the path, it'll just give us the first frame as a thumbnail. We can

get a thumbnail from a specific time five. So we're doing like 5 seconds in.

five. So we're doing like 5 seconds in.

That's how we're getting the thumbnail.

We can do transformations on the thumbnails. We can trim the videos so we

thumbnails. We can trim the videos so we only get a certain amount of length from it. And then of course the most

it. And then of course the most important thing in my opinion is the optimization. So you can do image

optimization. So you can do image optimization. So you can automatically

optimization. So you can automatically compress the images without losing quality and load them significantly faster. You also can do video

faster. You also can do video optimization and there's like so many different things. So if you do care a

different things. So if you do care a lot about image and video, definitely check out these docs that I will leave in the description. And one with video specifically is like changing the quality of the video so you're not loading, you know, massive 4K videos or

something. Um, and even if you set it to

something. Um, and even if you set it to like 90% of the quality, it's, you know, three times smaller, which is significant. So anyways, that's the

significant. So anyways, that's the images. They are, you know, working. Now

images. They are, you know, working. Now

I want to continue with the API. So we

have the ability to kind of get a feed to uh, what do you call it? Upload a

file. Now let's write the ability to delete a post. And then what I want to do is move on and talk about authentication. And so we actually have

authentication. And so we actually have different users kind of signing in and only the user who made a post can delete a post and like you need to be signed in to be able to make a post. That's pretty

important, right? So let's make another endpoint here. Let's call this at

endpoint here. Let's call this at app.delete.

app.delete.

For deleting, we're going to take in /ost and this is going to be a path parameter of our post ID. What we're

then going to do is say async define delete_ost.

We're then going to say postc ID and this is going to be a string. We're then

going to say the session is async session and that depends on the get async session. We're then going to have

async session. We're then going to have a try. For the try, we're going to say

a try. For the try, we're going to say the postc_uyu ID is equal to uyuid.uyuid

and then this is going to be the postc ID. We're then going to say result is

ID. We're then going to say result is equal to await session dot execute and

we're going to say select post dot where okay and we're going to say where the post do ID is equal equal just two

equals to the post underscore uyu ID.

Now the reason why we need to convert the post ID to a UU ID is because this will be a string by default and we need it to be this UU ID object. when we do the comparison they match. Okay. So then

after this we're going to say the post is equal to result and we're going to say dotscalers okay with a set of parenthesis and then dot first. What this is going to do is

dot first. What this is going to do is just return the exact result rather than giving us this kind of object that we need to loop through. So that's what scalers does even though I know it sounds a little bit confusing. We're

going to say if we do not have any post then we're going to raise an HTTP exception and we're going to say the post is not found with status code 404.

Okay. And then otherwise what we're going to do is just delete the post. So

we're going to say await session.de

post and then we're going to say await session do commit like that. And when we commit this it

like that. And when we commit this it will delete the post. We're then going to return and we'll just say success is true. And then we can have some message

true. And then we can have some message like post deleted successfully. And then

we're just going to have an except in case there's an error. So we'll say accept exception as e. And then what we're going to do is just raise an http exception saying hey there's some error.

This is the error. Okay. And that should be all that we need to do for deleting a post. So we can save that and let's now

post. So we can save that and let's now give it a test. So, let's go to here.

Let's grab a post ID. So, maybe one of these old ones. And let's refresh and let's go to posts. Let's pass in the

post ID and execute this. And it said 404 post not found. Um, okay. So, that's

maybe an issue. Let's go feed. And let's

try to get the post. And okay, it looks like it did delete that post maybe because it said 404, but then it deleted it. So, let's copy this. Let's paste the

it. So, let's copy this. Let's paste the other one and let's do it. And there we go. Okay, now it says success. True.

go. Okay, now it says success. True.

Post deleted successfully. Okay, so that looks like it's working. And then if we go back to the feed, we can execute. And

now we only have one post inside of here, which is a valid post. Cool. So

deleting is working. Upload is is working. Getting is working. Now what I

working. Getting is working. Now what I want to do is I want to start handling the user authentication. This is all great, but it only kind of matters if we can like sign in. And for example, if I make a post, you know, you shouldn't be

able to delete it, right? We have to have kind of rules and authentication and that kind of flow uh for our endpoint. So, let's go ahead and start

endpoint. So, let's go ahead and start doing that. To do that, I'm going to go

doing that. To do that, I'm going to go over to app.py. I'm going to make a new file, call this users. py. Now, this is where we're quickly going to talk about

JWT tokens. So, let me hop over to the

JWT tokens. So, let me hop over to the kind of I don't know whiteboard and explain that to you. Okay, so we're going to talk about authentication, right? This is arguably the most

right? This is arguably the most complicated part of most web applications. And for this app, we're

applications. And for this app, we're going to use something called JWT tokens or JWT O. JWT stands for JSON web tokens. They are a very common format

tokens. They are a very common format for web authentication. And the way that they work is that they essentially validate or authenticate a user by the user including this token in all of the

requests that they send to the server.

So this little diagram that I have for you explains it. Let's go through it. So

essentially the way this works is you have some user let's call her Sally right and she logs into the application.

Now before she can log in she needs to make an account but to make an account you don't need to do anything fancy. So

let's imagine you know she makes some account she has some credentials. Okay

now she signs into the uh server. The

way that she does that right is she goes from her computer. So she's on some website and she sends her login details to this O endpoint. So maybe that's her username and her password. Right now,

this is our API or kind of our server.

And what it does is it checks the user credentials and it says, "Okay, are these valid or are they invalid? They

should be valid." So, when they're valid, what's going to happen is it's going to generate a signed JWT token.

Now, this is a special token that just looks like a random string of characters that essentially identifies Sally. It

tells us, okay, this token belongs to Sally. So, if I see this token, it means

Sally. So, if I see this token, it means that Sally is the one who sent this request. That's effectively what that

request. That's effectively what that means. Sally signs in. She then gets

means. Sally signs in. She then gets some token back. And this token is Sally's token. Anyone that has this

Sally's token. Anyone that has this token is Sally in the eyes of our API.

Okay. So, what Sally does is she now stores this token or really her computer stores it in the browser. She's not

going to do it manually. And now for the rest of all of the requests that she uses with our um API, she sends this token along with the request. So, she

has the request plus this JWT token. We

verify the token is correct and then we say, "Okay, who is this?" Oh, it's Sally. Okay, great. So, it's Sally. So,

Sally. Okay, great. So, it's Sally. So,

we can now go do this thing because Sally's allowed to do that thing. That's

essentially how this works. This is an oversimplified explanation. The point is

oversimplified explanation. The point is user signs in, they get some token, they store this token, they then send that with every request as they um kind of hit our API and start interacting with

it. And that identifies them to us as

it. And that identifies them to us as that user. And there you go. Right? That

that user. And there you go. Right? That

that's how it works. Okay. So that's

what we're going to implement. Now to do that, we're going to use something called fast API users, which is a module that we installed that just makes this process a lot easier. So in our users

file, we're going to say import uyuid.

We're then going to say from typing import optional. And we have a lot of

import optional. And we have a lot of other stuff to import as well. We're

going to say from fast API import depends and request. And then what we're going

and request. And then what we're going to do is say from fast API users import the base user manager

the fast API users and the UU ID ID mixin as well as

models. Okay, now this is giving us an

models. Okay, now this is giving us an error because I need to make this fast API users plural. And now we're good.

Then we're going to say from fast API or fast API users.authentication.

users.authentication.

Okay. And we're going to import the authentication backend if we can spell this correctly. We're

also going to import the bearer transport as well as the JWT strategy.

Now with this you can use various types of token strategies. In this case we're going to use JWT. Don't worry, there's some other ones as well, but we're not going to look at those right now. We're

then going to say from fast API users.database

users.database import the SQL Alchemy user database.

And we're going to say from app db import user and get user DB, which are two functions that we're going to go and write now. Okay, so because we're now

write now. Okay, so because we're now going to have users in our app, we are going to have to make some changes. So,

we're going to go to database.py Pi and we're going to start writing a user model that we can essentially use to store uh users. Okay. So to do this

we're going to say from fast API users db import the SQL alchemy and this is user database. Also going to import the

user database. Also going to import the SQL alchemy user table uu ID. Okay this

is complicated that sounds crazy long but these are just what we need to import. And then what we're going to do

import. And then what we're going to do is beneath the base we're going to say class user and this is going to inherit

from the SQL alchemy base user table uyu ID and base. We're then going to say relationship.

Okay. And this is going to be post and then we're going to say this back populates the user. Essentially what we're doing

the user. Essentially what we're doing here is we're creating this um table, this user table, so that we can have a relationship between our posts and between our users. We want to know what

post was created by what user and what posts exist for what user. So we're

going to say post is equal to this. And

now on this user, we'll be able to find all of their posts. Okay, so that's why we're saying back populates user. So

what I'm going to do now on this post um database model is I'm going to create the relationship content to the user so that from a post we know what user posted it or what user created it and

from a user we know what post that they have. So on my post I'm going to do

have. So on my post I'm going to do this. I'm going to say my user ID is

this. I'm going to say my user ID is equal to column and then this is going to be uh what we want here uyu ID. We're

going to say as uyu ID is true. We're

gonna say foreign key and this is going to be user do ID and we're going to say nullable equal to false.

Okay. Now a foreign key is essentially a reference to another table. So in our case what we're saying is for this post we want to have a foreign key which

references the ID of a user. That's what

we're doing. So we know the user ID that posted this post that made this post.

Now, as well as that, we're going to create a relationship and we're going to say user is equal to relationship and then we're going to have user and we're going to say back populates posts. Now,

these relationships automatically link these objects together and allow us to use the post and the dot user attribute on both post and user and the foreign key allows us to have this link so that

we know the user's ID. Now what we've created here is what's known as a one to many relationship where one user can have many posts. There's different types of relationships that we can define in

our database models. This is not a SQL course so I'm not going to get into that you know too in depth but the relationships to be aware of are one to many, many to one and one to one. Most

frequently you are using one to many which means you have one user with many potential posts. All right. Now, if we

potential posts. All right. Now, if we wanted to flip the relationship around where one post had many users, for example, we would simply change the foreign key to exist on the user table

rather than on the post table. So,

typically the child, so in this case like one user has many posts. So, the

post would be considered a kind of a child of the user in terms of the relationship hierarchy is the one that contains the foreign key. Again, this is something you need to look at more if you're designing databases. And again,

this is not a SQL course. The point is we need to make this relationship. So

now users are linked to posts. Now that

we have that, we've created the user, it's inheriting from base as well as from SQL alchemy. We can go back to users and we can start using this. And

actually, sorry, there's one more function I forgot I need to write here.

So let's go down to the bottom and we're going to say async define get user DB. We're going to say session. And this

DB. We're going to say session. And this

is going to be the async session equals depends. Okay. Okay. And let's spell

depends. Okay. Okay. And let's spell depends correctly. And depends is a

depends correctly. And depends is a capital of course. We're going to say depends on get async session. And then

what we're going to do here is we're going to say yield SQL alchemy user database session and user. Now why is this giving me an error? I guess I

didn't import it. So let's go from fast API. So from fast API

API. So from fast API import depends with a capital D. And I

think that should be good. Now,

essentially what we're doing is we're just writing a function that's going to get us the user database table. Um, so

that's effectively what this is doing.

Again, don't worry too much about it.

The database stuff is a little bit confusing. The point is it will just

confusing. The point is it will just give us the database table that's associated with the users, which we're going to have to use here. Now, inside

of this users py file, okay, so from here, we're going to create some variable called secret. This should be equal to some random string. Um, you can actually generate this with a specific

function on your computer. Point is, you don't want to share this secret string because this is actually what's used to sign your JWT tokens, which identifies them as unique to this particular app.

If someone were to have access to the secret key, they would be able to decode your JWT tokens, which you don't want.

So, this is something that you want to keep secret, hence the name secret. In

my case, I'm just making it something random. So now what I'm going to do is

random. So now what I'm going to do is I'm going to say class user manager and this is going to be UU ID ID mixin. So

we're going to inherit from that. We're

also going to inherit from the base user manager. And then we're going to have

manager. And then we're going to have the user and the UU IDU ID. Okay. Again, I know some of this

ID. Okay. Again, I know some of this stuff seems confusing. This is directly out of the fast API users documentation.

You just set up one time and then you're good to go. You don't need to memorize it. Just bear with me. So now what we're

it. Just bear with me. So now what we're going to do is we're going to have the reset password token secret and the verification tok token secret both being equal to the same thing which is a secret. Can make it different if you

secret. Can make it different if you want but that's all that we need. Now we

actually don't need to do anything else inside of this class but I just want to show you that we can write various functions here so that we can handle things that happen when a user registers when they forget their password or when

they are requesting to for example verify their token. So what you can do is you can hook into all of these common user operations that are going to automatically be written for you by fast

API users. So we can do something like

API users. So we can do something like async define and then you can see there's a function like on after register and this is a function that's automatically

handled for us and what we can do is we can just say you know print you know user has registered and there you go right so after the user register boom this print function will run and if we wanted to do something specific we could

do that inside of here we could have another one like async define and then on after forgot password right and then boom we can do something on after request verify and then we can do something. I'm just showing you some

something. I'm just showing you some examples if you can hook into these. If

you look into the fast API users docs and you can control what's happening based on certain operations, it will be automatically handled for you. So now

what we're going to do is we're going to write a quick function. We're going to say async define get user manager and we're going to say the user

DB is equal to SQL alchemy user database and this is equal to depends get user DB. Okay, we're then going to yield the

DB. Okay, we're then going to yield the user manager with the user DB. So essentially we're

taking our database user kind of injecting that inside of here. And now

we have this user manager class which will allow us to manage the users in fast API. We then are going to have the

fast API. We then are going to have the bearer_transport which is equal to the bearer transport and then we're going to have our token

URL be equal to o/jwt/lo.

So when someone wants to log in they go to this endpoint and then they can pass their credentials and they can log in as a user. We're then going to say define

a user. We're then going to say define get_jwt strategy. And this is going to return

strategy. And this is going to return JWT strategy. We're going to pass our

JWT strategy. We're going to pass our secret and we're going to pass our lifetime seconds. Now, the lifetime

lifetime seconds. Now, the lifetime seconds is how long you want a JWT token to be valid for before the user needs to sign in again. I believe this is 3600

seconds, which is going to be um what is that 10 minutes or 1 hour or something?

Yeah, I think Yeah. So, sorry, this is 1 hour. So, 60 minutes is 3600 seconds.

hour. So, 60 minutes is 3600 seconds.

So, you can change how long you want the token to be alive for essentially. And

if you want to invalidate the token after a certain period of time, by default, JWT tokens have some lifespan.

The longer you make them, the more convenient it is for your users, but also the less secure because that means like you know someone could come onto your computer for example and they would um you know be able to just start using

the application because the JWT token is still alive. Okay, now we have the JWT

still alive. Okay, now we have the JWT strategy. We're going to define the off

strategy. We're going to define the off backend which is going to be equal to the authentication backend. We're going

to say the name is equal to JWT. The

transport is the bearer transport. And

we're going to say get strategy is get JWT strategy. Okay. We're then going to

JWT strategy. Okay. We're then going to say fast API users is equal to fast API users user uuid.uid

get user manager and o backend. So when

we define fast API users, what we do is we specify this is the user model that we're using and this is how we get the user manager. This is the backend that

user manager. This is the backend that we're using which is JWT tokens. Then we

say the current active user is equal to fast API users.curren user active equals true. What this is going to do is when

true. What this is going to do is when we call this current active user function, it's going to automatically give us the current active user by going and checking the user's JWT token.

Again, I know this stuff is confusing.

You're not going to understand a lot of the stuff that's being written. The

point is this framework when you do the little bit of setup that we're doing here will automatically handle all of the authentication for you. We just need to kind of hook it up and do this setup.

Once we do this setup, all the JWT off will be handled automatically and all you need to do is just use this which you're going to see. So now we've written everything that we need for users. py. So what we're going to do is

users. py. So what we're going to do is go back to app.py and we're going to start actually using this because now we need to essentially connect different endpoints to this um what do you call

it? JWT kind of backend which you're

it? JWT kind of backend which you're going to see. So now that we've done that, we're going to import this. So

we're going to say from app dot users and we're going to import the oback backend.

Okay, we're going to import the current active user and we're going to import fast API users. Now what we're going to do is for our app, we're essentially going to connect the different O

endpoints that we need to our fast API users endpoint. So you'll see what I

users endpoint. So you'll see what I mean in a second, but we're going to say the following. We're going to say at

the following. We're going to say at app.include include routouter and we're

app.include include routouter and we're going to include the fast API users.get

offers routouter with the offc_backend and we're going to say the prefix for

this is equal to slash off slashjwt and we can say the tags is equal to off.

Now, what we're doing here is we're saying, okay, in my app, I want to include all of the endpoints that are automatically provided by fast API users. So, I'm just going to say

users. So, I'm just going to say app.include router, and I'm going to

app.include router, and I'm going to connect it to all of the endpoints here.

And I'm going to prefix this with /jwt, which means I go to /jwt plus all of the endpoints that are automatically included by my fast API

users um kind of module that I brought in here. Okay, so things like resetting

in here. Okay, so things like resetting your password, uh, you know, after you forget the password, what happens? All

of those endpoints are automatically written and handled here for you, and we just include them into our app. You'll

see what I mean in a second.

Essentially, we're just including some routes that are automatically written inside of fast API users in our app.

Okay, now we're going to keep going because there's some more routes that we need to include. So, we're going to say app.include router, and this is going to

app.include router, and this is going to be fast API users.getregister routes.

This time we're going to prefix it with slash off and the tags will be off.

However, for the register routes we need to pass in some schemas which we're going to write in a second which is user read and user create and then we're going to go write those in schema. So

let's do that really quickly and then come back and I can explain what we need. So for user read what we need to

need. So for user read what we need to do is we need to say from fast API users import

schemas. I then need to import UU ID. So

schemas. I then need to import UU ID. So

I'm now going to come and I'm going to say class user read and this is going to be from schemas.base

user and this is going to be UU ID doU ID. Okay. And then this is simply going to say pass. I'm then going to say class user create. This is going

to be schemas.base userreate. And then

I'm going to say pass. And I'm going to say class user update is going to be schemas.base base user update and then

schemas.base base user update and then pass. Now, these are schemas that

pass. Now, these are schemas that automatically come from fast API users, but similarly to some of the schemas we had before, we need to just create our own kind of dummy um schema that

inherits from it that we could then override if we want to. So, that's

exactly what we're doing. Now, we're

going to go back to app and we're going to import the schemas that we need. So,

from apps schemas, we're going to bring in the user read the user create. Okay.

And the user update which we'll have in a second. All right. And now this should

a second. All right. And now this should be good to go. Okay. So that's that for the registration routes. So again, same thing. We're now going to have the

thing. We're now going to have the ability to register automatically be created for us. I'm going to show you this in the documentation in a second from fast API users. Now if we wanted to bring in other routes, we can do that.

So for example, we can say at appincclude routouter and then we can say fast API users.get get resert reset password

users.get get resert reset password router. Right? And now if we do that, we

router. Right? And now if we do that, we now are have the ability to reset the password. Now let's keep going. Let's

password. Now let's keep going. Let's

say app.incclude router and we can do the get verify router. Now this one we actually need because it will allow us to verify user. So we bring that in and then notice automatically we bring in

user read. And then lastly we can have

user read. And then lastly we can have get users router. So I'm going to say app.incclude include router get users

app.incclude include router get users router and then we can include the user read and the user update. Okay, so let's

quickly just reload this and I'm just going to shut this down and restart it uh so that we can test and make sure it's working. So now if I go here you

it's working. So now if I go here you can see that I have all these new routes that are popping up right like login register forgot password reset password request verify token verify users me

users me users ID user ID user ID right all of this kind of stuff that I'm able to now utilize because I'm using fast API users again I'm not going to go through literally every single thing here but I will show you the basics so

what I want to do now is I want to register a new account so what I can do to register is I can go try it out And I'm just going to do a new new account here. So I'll go tim at techwithtim.net.

here. So I'll go tim at techwithtim.net.

And then for the password, we'll go one, two three four five six seven eight. Okay, we'll just make is active

eight. Okay, we'll just make is active true. And then we won't set anything for

true. And then we won't set anything for the super user is verified. Uh you can change these so you don't pass these when you register later on, but for now in kind of debug mode, that's what we're doing. So actually, let me just change

doing. So actually, let me just change this like timwithtim.net.

Let's execute this. And then it's going to now give me my ID, my email, and then all of this information. And now what I can do is I can sign in with this user.

So what I'm going to do is I'm going to go to authorize. I'm going to pass my email and my super secure password and press on authorize. And now it's going

to essentially sign me in. Now that I'm signed in, it's going to give me this token. And what will happen is whenever

token. And what will happen is whenever I send any requests, it's going to use this token. So now I can go to for

this token. So now I can go to for example users me and I can just send the request here and you're going to see that it tells me hey I am tim one attewithim.net and notice that

automatically this super long token was included in my request because that's how this works. So if you sign in here with authorize then by default this token that identifies you is going to be sent in all of the future requests as

you're using this documentation and you're going to be able to verify if you're user or if you're signed in or if you're not signed in etc. So now all the user stuff is working. However, we need

to associate users with the posts and we need to make it so that I can't actually call these endpoints like upload feed or post unless I'm signed in. So let's do that. So I'm going to go to main.py. And

that. So I'm going to go to main.py. And

the way that I can make some of these routes what's called protected is I can add a dependency that forces the route to get the current active user. And if

the current active user doesn't exist, it won't let me call this endpoint. So

for example to be able to actually make an upload well I need to have a user right like I need to be signed in as a user. So what I can do is I can just

user. So what I can do is I can just change the function to be like this. So

I can just say user colon and then I can say user and I can say this is equal to depends and this is current active user like that. For user I can just import

like that. For user I can just import that from my database. So let's just import user like so. And now what will happen is if I try to call this function and I'm not signed in and I cannot get

the current active user this function will not work. So literally all you have to do now is if you want to protect these routes you just add this dependency. So for example for the feed

dependency. So for example for the feed same thing we add the user we say okay you know it's just a get current active user and now it won't work unless we have the user. Now same thing for the post we're going to get the current

active user. So let's do that. And we're

active user. So let's do that. And we're

going to have to change some of the content of these functions now so that it actually saves the user that is doing this operation. So let's go back to the

this operation. So let's go back to the DB and for our post we're now associating with users. Okay, so that's all good. But for our app when we are

all good. But for our app when we are uploading images, we now need to associate them with that user. So for

our upload result here, let's take user ID and let's make this equal to the user do ID. So now we're storing the

do ID. So now we're storing the particular user for every single post.

Okay, so that's good. That's all we need to do there. Then for deleting the post, we need to only allow the user to do this if they're signed in as the correct

user. So once we check for the post down

user. So once we check for the post down here, we're going to say if the post dot user ID does not equal the user do ID,

then we need to raise HTTP exception. So

let's do this. Okay. And we're going to say status code 403, which means unauthorized. You don't have permission

unauthorized. You don't have permission to delete this post. So now if I try to create a post with an account that didn't make this post, or sorry, I try to delete a post with an account that didn't make it, it's not going to allow

me to do that. Okay, so now we've just added the authorization check and I think that is pretty much good. Now

we're going to go to get feed. And for

get feed, we're going to make some enhancements here so that we actually know which user made these posts in the feed. So first things first, what I'm

feed. So first things first, what I'm going to do is I'm going to include the user ID in my response here. So I'm

going to say user ID is equal to the string of post dot user ID. And I'm also going to include if we are the owner of this post so that the front end knows

that. So we're going to say is owner and

that. So we're going to say is owner and we're going to say post dot user ID is equal to user ID. So now we're checking all right is the user ID of this post

equal to our ID. If it is, that means we made it. If it's not, well, we didn't

made it. If it's not, well, we didn't make it. Okay. And then I think that

make it. Okay. And then I think that should pretty much be good. But there's

one last thing actually that we will do.

Okay. So, for every single one of our posts, I also want to include some basic information about the user. And in this case, that's going to be their email.

And what I'm going to do is I'm going to get the user's email. So, I'm going to say email. And then I'm going to say

say email. And then I'm going to say this is post do user do email. And I

think that will work. Uh, but I'm not 100% sure. Let's see. Okay. Okay, so now

100% sure. Let's see. Okay. Okay, so now we kind of have protected our endpoint so that only authorized users are able to use this. And that should pretty much wrap up the API, but of course we want to test this. And then I'm just going to

have a little simple front end that I'll show you how to use so we can actually see it visually. All right, so let's authorize ourselves by signing in with that account. So we're going to say tim1

that account. So we're going to say tim1 techwithtim.net.

techwithtim.net.

Okay, if we can spell this correctly.

All right, then we're going to have 1 2 3 4 5 6 7 8 and authorize. Okay. So now

let's go. Okay, that's fine. From here,

let's go to the feed and let's try to get the feed. Okay. And when we get the feed, gives us internal server error.

Let's see what the problem is there.

Okay. And of course, the error came from this where I'm getting the post do user.

Um that is not working properly just due to how we're loading the user. So I'm

going to do another approach here. This

is a little bit more complicated, but will allow us to get the emails. So I'm

just going to say result is equal to a weight. This is going to be

weight. This is going to be session.execute

session.execute and I'm going to say select user. Then

what I'm going to do is say users is equal to row zero for row in result doall.

I then I'm just going to create a list of all of my users. This is not the most efficient way to do this but for this example it's fine. So we're going to say user dictionary is equal to and this is

going to be u do ID and this is going to be you do email for you in users.

Okay. Now what we're able to do is we're going to be able to get the user's email like this. So to get the email we can

like this. So to get the email we can simply say user_dict and then this is going to be do get and it will be post do user id otherwise

we'll just put unknown. Okay. So now

this if we save it should reload. Okay.

And now if we go back to the feed let's try it again and you see now that we get the post and it is working and saying we are not the owner of this post because we were not signed in as that user. So

now if I take this post ID right and if I try to delete this post you're going to see that it doesn't work. So let's go here because I'm not signed in as the correct user. So let's go here and try

correct user. So let's go here and try to delete. Execute. And you see it says

to delete. Execute. And you see it says you don't have permission to delete the post. Perfect. Okay. So that wraps up

post. Perfect. Okay. So that wraps up the API. The API is working. It's fully

the API. The API is working. It's fully

functioning. The next thing that I'll quickly show you is how we can get a nice little user interface here. So we

can actually play around with the UI.

Now, I'm not going to write the user interface from scratch. If you want all of the code for this, it will be linked in the description down below. You can

simply copy it and paste it inside of here. What I'm going to do is just make

here. What I'm going to do is just make a new file. And I'm just going to call this frontend. py. I'm just going to

this frontend. py. I'm just going to copy a bunch of code that I've written previously, which is the front end, and paste it in here. Okay. Now, this code uses something called Streamlit, which is something that we need to install.

So, what we're going to do is we're going to keep our back end running.

We're going to go into a new terminal, and we're going to type uvad streamllet.

Now, that's going to add Streamlit to our dependencies, which is going to allow us to now run this front end. So,

again, the all of this code that you see will be available from the link in the description. You can literally just copy

description. You can literally just copy it into a file called front end. And

this is going to handle essentially interacting with the API that we just spent all of that time writing. I will

go over how it works in a second, but let's just quickly test it. So to do this, I'm going to type essentially uv run streamllet run main dot or not main.

This is front end. py. When I do that, it will start running streamllet. It

should just open it in your browser. And

then you have a user interface. What you

can do is you can type in an account like Tim attechwithim.net.

You can type in the password. When you

do that, you can either sign up and make a new account or you can just log in.

And if you press log in, it should bring you now, let's wait a second, to the feed. Um, failed to get user info. Okay,

feed. Um, failed to get user info. Okay,

interesting. So, we'll fix that in a second. Uh, but it should bring you to

second. Uh, but it should bring you to the feed once I fix this problem. Okay,

and you can see here that it now loads the feed. We have my username, the date,

the feed. We have my username, the date, the image, and then we can delete this.

And we can also expand it directly from here. Now, I want to talk about kind of

here. Now, I want to talk about kind of how this works. So, I'll walk through the code a little bit, but again, just copy the code from the link in description. It's not really valuable

description. It's not really valuable for me to write this out with you because this is not a tutorial on Streamlit. Now, first things first, the

Streamlit. Now, first things first, the JWT token is something that we store in our session. That just means that we're

our session. That just means that we're storing it. So, we're constantly using

storing it. So, we're constantly using it anytime we send a request to the back end. Okay. The way that you send JWT

end. Okay. The way that you send JWT token requests is you include bearer plus the JWT token. And then when you do that, you're able to actually send an authenticated request. You saw this in

authenticated request. You saw this in the examples when we were looking at the documentation from fast API, but I'm just doing it directly kind of manually here in Python. Again, I'll show you how

the request kind of looks in a second.

So here is the login page, right? So

when I want to log in, what I'm doing is I'm just passing a username and a password and I'm passing it to this URL.

So O JWT login, right? Passing my data and then I'm able to log in. Now when I do that, I get some token data and I store that access token in my state. So

I'm able to use it as my JWT token to sign in. I then get my user info by

sign in. I then get my user info by passing a request to user/me so I can make sure that I'm signed in successfully. And I store that again in

successfully. And I store that again in my session state. Same thing for registering. I send a request to

registering. I send a request to allregister and then after I register I send another request to get my JWT token um so that I'm good to go. Okay. Now we

have the upload page. On the upload page what I do is I have files right? So I

have a file which is the uploaded file that I select which I'm going to show you in a second and I have a caption. I

then include that in the request to upload, right? As well as my headers

upload, right? As well as my headers which include my JWT token that's then able to upload the image and then show it on the feed. Now, the cool part here is when we start talking about actually

displaying the images with image kit because it makes it super easy for us to view the images and to actually perform transformations on them. So, let me show

you with the UI. If I go here and I go to upload. Okay, so let's go to upload.

to upload. Okay, so let's go to upload.

Let's change this here and let's upload here this one with maniv and me which is a testimony and I'm going to say hello world dev launch worked okay because this helped him land

a job. Let's go share and then it's

a job. Let's go share and then it's going to upload this file for me to my backend API. And if I go back to the

backend API. And if I go back to the feed now just takes a second to load.

We'll see the image appears here. And

one thing you'll notice if I make these larger is that we have this caption that I'm kind of putting directly on top of the images by using image kit where I say hello world dev launch work. Now

it's quite small. I'm going to show you how to make it larger. But the way that I do that is from my UI before I load the image. So if we go down here, let's

the image. So if we go down here, let's do this. You can see that I have these

do this. You can see that I have these file types. So I check if it's an image,

file types. So I check if it's an image, which is all we've done right now, but I'll show you videos in a second. Then

what we'll do is we will essentially transform the URL to use the transformation that puts the caption directly on top of it that looks like this. So this is essentially the text

this. So this is essentially the text that you use. If you want to add a caption, if I want to make it bigger, I can say like font size 100 and then it will make it much larger and then it directly transforms the image from me

from this one URL and passes it back very quickly. Okay, so that's how I'm

very quickly. Okay, so that's how I'm kind of um transforming this. Now, I

want to show you uploading a video, which we'll do in one second, um, and then displaying the caption for that video. But that's kind of how um, I'm

video. But that's kind of how um, I'm doing that transformation with ImageKit and displaying the images. So, let's go back. And now, if I refresh this, uh,

back. And now, if I refresh this, uh, let's sign in again. So, 1 2 3 4 5 6 7 8 and go log in. Then, let's wait a second

here. Okay. And we'll go to the feed

here. Okay. And we'll go to the feed and okay, get rid of that. And you can see now it's quite a bit larger cuz I made the font size 100. If I made it like 1,000, obviously it would be even much bigger. And you can see the text

much bigger. And you can see the text shows up on the image. Now, if I want to upload a video, I can totally do that as well. So, let's go files and let me find

well. So, let's go files and let me find a video. Okay, so I just found this

a video. Okay, so I just found this screen recording that's not that big.

So, I'm just going to upload this screen recording. So, you can see right there.

recording. So, you can see right there.

Going to go ahead and press on share.

Because it is a video, it will take a little bit longer to upload. So, we'll

just wait for that to complete. And

then, as soon as it's uploaded, okay, so let's go back to the feed here. We

should be able to see it directly from image kit. You see it's going to take

image kit. You see it's going to take one second to load here and then there you go. We get the video and we can

you go. We get the video and we can watch it, right? And it just shows up directly here. Now, same thing with when

directly here. Now, same thing with when we transform the images, we can transform the video. So, let me show you a few examples of how we actually do that. Let's go here. And what I'm going

that. Let's go here. And what I'm going to do is I'm just going to put in some transformation parameters. Right now,

transformation parameters. Right now, you can see that I'm just putting it quality at max and width 300. But I can adjust this to, for example, crop the video. So, for example, if I just take

video. So, for example, if I just take this transformation parameter, I'll just show you what this does, but essentially it crops the video and then adds a uh blurred background and puts it in vertical format for me. In this case, it's already vertical, but if it wasn't

vertical, it would do that. So, if I go back to my was it example here UI, let's just go back to the feed. So, it

reloads.

Okay. And actually, you can see that this did work now. So, it resized to be quite small. And you can see now that we

quite small. And you can see now that we have kind of this video like in the middle and then we have this blurred background which is exactly what I got the transformation to do. Um the quality is quite low obviously because of how I adjusted it and the size that I made it

but you can see that it is working and sorry if I just scared you there with that audio. Um that scared me as well

that audio. Um that scared me as well but the point is it is loading. Um cool.

So I think that's pretty much it guys. I

mean that covers everything that I wanted to show you. We made a application that's able to post photos and videos, is able to handle user o connected to a database, has all kinds

of different more advanced features that you typically don't see in more beginner tutorials. And while I know this was a

tutorials. And while I know this was a really long video and a lot of code, I wanted to be super detailed and covered everything in as much depth as I possibly can. If you guys enjoyed this

possibly can. If you guys enjoyed this video, make sure you leave a like, subscribe to the channel, and I will see you in the next one.

[Music]

Loading...

Loading video analysis...