FastAPI with PostgreSQL and Docker

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] what's going on you guys and welcome back to the channel first of all before i start i just want to give a big shout out and a big thank you for everyone who's been supporting this channel who's been hitting that subscribe button the like button and also commenting as we've now hit the 1000 subscriber milestone so big thank you i'm really hyped i'm really excited for more content that i've got prepared for you guys and hopefully more uploads on a much more regular basis but yeah so in this video we're going to be looking at fast api with docker and postgresql so to actually begin or before we begin there are two things that you'll need to download if you want to follow along with this tutorial the first one is postgres sql and that you can find on the postgresql downloads page so postgresql.org forward slash downloads and there you'll find the right distribution or package for your operating system so linux mac os windows the second thing is to have a docker installed and you can go to docs.docker.com forward slash get docker so this thing here i'll put those in the link down below in the description below but you'll find the distribution for mac for windows and linux so yeah i'm not going to go through all this through the installation process as first of all it'd be it'd vary if you were on a windows system as i'm on a mac um so yeah it may not be that helpful for someone on windows but yeah the installation for both is pretty smooth but yeah once you have both of those two things downloaded postgresql and that's needed more for our fast api application in order for it to communicate with the postgres database uh less so for the database itself and you'll see that later on in the video and yeah docker is a pretty easy one to download and install so once you have both of those uh installed the first thing we're going to do is actually create our docker container so our postgres docker container this will just host our database and first of all just to ensure that you have docker installed you can just do docker v and you'll see the version that you installed maybe not same version as me but most likely either this or one in the future one in the future so yeah let's get started with creating our container so the first thing to do is i'm just going to clear this but you want to pull uh docker post press so docker pull and then postgres colon alpine so just like a minimal version of post press hit enter and you'll have it and then to see what you have installed you can just do docker images and yeah i have a few others like ubuntu etc but you have this is the one that you want okay so i'm just going to clear that the next thing is actually to create our container so to do that it's a rather long command so take your time with it and just make sure you have everything written properly but docker run and then dash dash name so the name of our container i'm going to call this fast api postgres and then dash e and then you want to set the password so and this has to be all in uppercase so postgres underscore password and then equals and i'm just going to name it password just for the sake of this tutorial and then dash d dash p and then the port so five four three two colon of five four three two and then you wanna specify what distribution so postgres colon alpine so yeah take a second to um write that down uh it's a rather long command so um yeah don't worry if um you may make a few spelling mistakes just as long as it looks like this in the end so docker run dash dash name the name that you want to give this you couldn't is i'm leaving up to you i'm just going to call it fast api postgres e and then sending the password the port so 5432 and that's typical that's the typical postgres runs on and then postgres colon alpine and then hit enter and then to see what containers we have we can just do docker ps and this kind of like the size of this has kind of cut this table up a bit but we have this container here you can also see uh what containers you have if you've installed the the gui for um docker which is this so i can see here that i have fast api postgres running as color here is green so yeah that's the container and it's up and running as well but we want to actually create a database out of it otherwise it's pretty much a useless container so to jump into it type in docker actually let me just clear it so type in docker and then exec so exec which is execute t so interactive mode and then the name so fast api dash postgres so the name you gave your container and then space and then bash so now we're in bash mode inside of our container you can list it out see what we have but we want to jump into postgres so type in psql-u and then postgres and you'll see this postgres here okay so let's go ahead and go ahead and create our database so to do that we'll say create database and make sure it's spelled properly so create database i'm going to call this fast api underscore database name it whatever you want we have this create database the next is to get create a user with a password for this database and this user will need when connecting our fast api application with our database so to do that let's just create user and then the name of your user i'm just going to call it my user with encrypted password and then the password itself so make sure you do this in singular quotes double quotes will raise an error so i'm just going to call it pass word like that and then semicolon at the end so now we have our user next thing is to actually give the privileges for our database our fast api underscore database to this user my user to do that just type in grant or privileges on database and then the name of the database so fast api underscore database to uh the the name of our user so we named it my user and then semicolon at the end and then you should get this grant in all uppercase that cool so now we can actually jump into our database so in order to do that you can do backslash c and then fast api database and there we go so we have fast underscore uh fast api underscore database so yeah that's our database created inside of our container but what we want to do is actually like right now it exists only inside this container but we want to make it accessible outside so to our fast api application which we'll be writing locally and not in a container so we'll say psql and then dash h and then localhost and then we want to specify the port which is 5432 and postgres enter and yeah that should now be available outside of this container and now we can jump into our python our fast api application so i've opened up another tab in my terminal and in this one i've just um created a directory so the fast api dash postgres docker and in here this is where all the code will live the code will also be available in the github description uh in the grit github link that i will provide in the description but to get started let's create our virtual environment so python3 dash m and then v-e-n-v v-e-n-v so create our virtual environment and then we can see it here with uh vnv next next let's activate it so source venv bin activate and you should see something to hint towards that you are inside your virtual environment now let me just zoom in a bit more but the next thing is to actually make the uh necessary installation so i'm going to do pip 3 install and then in double quotes fast api brackets all like that uh for some reason it complains when i don't when i do an installation with square brackets it complains so i have to just wrap it around in double quotes and then sql and then alchemy and then finally we want the [Music] psycho pg2 dash binary now it's spelled in kind of a weird way so it's psycho pg2 dash binary and this is cutting it a bit but let me just zoom out a bit so we want fast api sql alchemy and then psycho pg 2 dash binary and there's another distribution called cycle pg2 um for some reason sometimes i have a bit of trouble working with that one um but the dash binary is just another version of it i'm not really sure how different it is i guess i don't know maybe it's executed or it's compiled onto i don't know something binary related but i'm gonna go ahead and use this one and then just hit enter give that some time to install okay so now that we have the packages installed let's go ahead and open up the ide so i'm going to use vs code and i have it configured so that with code and then period it will open up within that directory enter and there we go so yeah let's get started first of all i'm just going to go ahead and change the theme a lot of you guys ask me what theme i use as it seems to be a recurring comment but to kind of highlight it in this video i tend to use noctis high contrast this one here and if you just search that in the extensions you should be able to find it so noctis maybe contrast and i think it's this package uh no this one here so noctis high contrast this is the one that i use but yeah so let's get started with first connecting with our database now first of all it's this tutorial is very similar to or the rest of this tutorial will be very similar to some of the other videos i've done in the past so my fast api with sql um i kind of had in two minds to just connect it up with fast api but i thought maybe just to go over and create like a very very basic api with it anyway um so we'll just do that in this one and yeah so let's first create our underscore underscore init underscore file py i'm just going to zoom in a bit but which maybe that might be hopefully this should be okay for you guys but uh yeah next we need our database dot py file i'm just going to close the init file but in this file we want a couple things it's again very similar to something i've done in a previous video but first of all we want to import sql alchemy as underscore sql next we want to import declarative from sql alchemy dot exec exec text and then declarative has underscore declarative and then the orm so import sql alchemy.orm has underscore orm and yeah i'm just going to install black that's just to format the code in a much more readable way and as soon as that's installed but yeah i can just continue i guess um i'm just going to shrink that then okay so let's first of all create our database url so with postgres it's quite simple we just want to say postgres close that there postgresql colon dash dash and then you want to specify your user and i named mine my user colon password that was the name of the password so uh yeah whatever you set as your password put that here i set mine as just password so just keep it as that and then at local host and then forward slash the name of your database now i cannot remember correctly what i named it so i'm just gonna go back i called it fast api database okay so in my case fast api database so that's the i already had it installed oh maybe it's still installing okay let's click save okay so next we want our engine so we'll say underscore sql dot create engine and then we want to pass in the database url next we want our session local and this is to create a session for our database with sql alchemy underscore orm dot session maker and then auto commit set that to false and then auto flush we'll set that to false and you can't see it because of um but yeah and then finally we want to bind it to our engine i don't like the fact that it's covering it but yeah we want to do this we want to write um also commit as false these the arguments auto flush as false and bind engine to the engine that we created next we want to create our base class and that is just simply doing declarative dot declarative base so that's basically connecting up with our database we can then use this for our models so or this base class here as our mod for our models let's create a new file we'll call this models dot py it'll only contain one model anyway but let's just make the necessary import so first we want date time this will be one of the types for one of our columns we'll import it as underscore dt next we want to import sql alchemy as underscore sql and then finally our database file that we created says unscored database okay so this api is just going to contain some contacts so someone's name last name email phone number all that so we'll say contact and then underscore database dot base and then we'll just give it a table name so underscore underscore table name underscore underscore contacts the id which is going to be an integer so underscore sql dot column and then we'll say underscore sql dot integer i'll stop showing up i think it's because i'm zoomed in so much that's why and then primary key we'll set that as true and we'll just set index to true as well yep and then we'll have the first name and let's just copy this and just change some of the arguments this will be a string primary key will not be true index will be true we'll have the last name which is same as the first name have it like that we'll have email which again is pretty much the same so we'll set this one as email we'll have the phone number which is again we'll store that as a string um yeah so we have our that we have our email we also we can just for kicks we can just set this to being unique and that you cannot add another person with the same email um and then a phone number we can also set this as unique equals true just to give it just to spice it up a little bit and then let's add our date created as this tends to be a field in most tables and we can say sql.column and then underscoresql.date time and we can just set the default as default equals underscore dt dot datetime dot utc now cool so that's our model there's nothing much there's nothing really you know special about this model but now let's go ahead and create our services file and in that we'll first go ahead and write our create database uh function so to do that um what we need to do is first go ahead and make the necessary imports so we want the database that we created so database has underscore database and then let's create a function so underscore create database and then what this will do is just return underscore database dot base dot meta data dot create underscore all and we'll bind it with underscore database dot engine so this will just create our um like database uh or bound our models to the database that we already created as we already created one back here with um [Music] fast api database so what this is really doing is just it's not so much creating database but yeah updating it or adding our tables in so we can actually call this add tables cool so now let's actually go ahead and run this so i'm just going to clear this terminal hopefully you guys can see this all right but the size should be alright i'm just going to increase it a bit and also lift this up but let's run python let's import services actually before we do that um before we actually do that like go back to services we also need to import the models so import models as underscore models okay this is so like this function is aware of of this i'm just going to exit out of this clear it and then python again so import services and then services dot underscore create is it not going to auto complete underscore database and ah it's called add tables that's why um so yeah instead of that say services dot underscore why is it messing around services dot underscore add tables and yeah so we now have added our contact table to our database and if you actually go back to the um command line if you still have your postgres container running you can actually list out the tables so we have if you do backslash and then dt this will show all the tables that you have so we have our contacts and we can just say select all from contacts and this wants to yeah i don't know why that showed up i don't know what's wrong with my computer today but yeah we have the id the first name the last name the email phone number and date created so that's pretty much it when it comes to just creating our database and adding it to post fast api but i'm going to continue with actually building a basic api just in case you guys are wondering so i'm just going to close the terminal zoom out a little bit um and yeah let's actually get started with creating so first let's create our schemas dot py file so schemas dot py and basically what a schema kind of acts as is a um our or pedantic models um they act as kind of like our serializer so we don't actually write serializers in the kind of traditional sense we just you make use of pedantic which kind of does it all for us which is one of the great features of fast api so first we need to import date time as we need this for our date created field oops as underscore dt we also want to import pedantic which comes installed with fast api okay let's first create our base class for our contact so we'll say class underscore base contact and then underscore pedantic dot base model we'll have the first name which is a string we have the last name which is a string we have email which is a string a lot of strings um what else do we have we have the phone number um which we've set as a string as well so phone under school number string and that's pretty much it so you're probably wondering why haven't we added id and the date created as this is our base contact other classes will inherit from this in all cases for both like posting or updating we'll always have these four the id will not exist if we're creating something because when we create an object the i did doesn't exist at that time at that point or um neither does the date created and also when we create our put endpoint there as well we don't want to update stuff like the id or the they created these are kind of immutable fields at that point so we'll first create our contact class this will be base contact so when we actually return a contact we also want to include as well as these four we also want to include the id which is an integer and the date created which is a date time object so d underscore dt.daytime next we can create our create contacts pedantic model and this does nothing just inherit this is just more for naming and clarity so based contact and we can just say pass because when we create we'll only be adding these elements in and just to check first name last name email and phone number yep so that's our schemas not so much schemas um so we can close that now let's actually i'm just going to close the database and models because we need now the main dot py file so inside this this is where we're going to be writing our api so the first thing is to import fast api as underscore fast api you also want to import the orm so import um actually better still what we could do is just import typing so from typing imports type oops type checking and also list so we'll need that as well and just here we can say if type checking then from um or from sql alchemy dot orm [Music] um import session like so and that's just for typing purposes it doesn't do anything else um but let's actually create our app so app equals and it's called fastapi.fast api cool so first let's create an endpoint that allows us to create a user so we'll say app.um post we'll say forward slash again that's showing up forward api forward slash contacts and the response model will have as schema from our schema so we need to import schemas import schemas as underscore schemas say schemas dot contact and then we'll say async and create underscore contacts this will have the contact that we pass in and this will be of type create contact and we also want our db so our database sessions are orm we need to import that from sql alchemy import um or maybe just from import sorry sql alchemy dot forum has underscore orm um dot session i don't know where i'm going with this equals fast api dot depends and then underscore services and we need a function that will get a db so this will automatically create a database session what we want is a function inside our services that will um create a database session so first of all i'm just going to import services as underscore services and in here we'll say get underscore db this function of course does not exist right now but we'll go ahead and write that oops so this just formatted it using black but yeah that's why you just saw it kind of shift so inside of services let's create a new function that will create a database session we'll say get underscore db and what this will do is say database dot session local and then we'll say try yield the database and then finally we want to close it so whatever the case always close your database session never leave them open so that's our get db now um yeah so let's go ahead and actually write a service function that will create a contact so back inside of services let's create a an asynchronous function create contact this will take in and we need to import schemas import schemas as underscore schemas and our contacts will be underscore schemas dot create contact and the db is just i don't know why that imported final but from typing we can actually import type checking um if type checking we can say from sql alchemy dot orm uh import session like so and now what this allows us is just to say the in double quotes is of type session it's an interesting way of kind of like adding some form of typing to python but this is one way which kind of encourages um readability but the return type for this is just going to be a contact so what we can do now is i just say paths and just like that format but we can now go ahead and create the contact so contact equals underscore models dot contact and inside that we can unpack contact dot dict so that will take the first name last name email all that and just unpack it and fill it in rather than us having to specify each argument ourselves just to help this a quick way of doing it then we can say db dot add and then contact so add contact to our database we want to commit it we then want to do db refresh on that contact and then finally let's return the schemas dot contact dot from or um so convert this contact into our contact schema back into that so in main dot py we can now say return await as i say synchronous and then services dot create contact will pass in our contact as the contact and our db as db so yeah we can actually go ahead and test this out now so to do that just open up your terminal clear all that and just zoom in we can say is python or not python sorry uv icon main colon app dash dash reload hit enter get that up and running and we can now go over to localhost port 8000 and we have our create contact so let's try it out fingers crossed everything works out fine so let's say the first name is john and then last name doe give him john gmail.com phone number just say that execute it and we get an internal server error and that's because we don't have orm mode uh set to true this is a good catch and something i well obviously forgot to do but back in our schemas we also need to allow from orm so this function that we're calling just zoom out this from orm that we're calling here you have to actually give permission to make that call so if we go back into contact in here we'll say we'll create another we'll create a subclass called config and in that we'll say orm mode equals true this still should have added him into the database as um it basically failed when we did that from rm before all that we kind of added it so if we actually go back to our database here select all you can see let's just zoom out a little bit you can see that we have john doe john gmail.com the phone number date created or added into the database so yeah that part works let's actually try it again and get a valid response this time so if i say something like um jane doe jane gmail.com execute it again another sub internal server error and this is because uh the number already exists so good the validation's working kind of like how my errors are leading to actual checks into what we wrote it's kind of a good sign so i'm just going to change the phone number uh execute it again and we have the response body as jane doe jane gmail.com all that and unfortunately not an error this time so let's actually select all from contacts and you can see now the id is now three because i think well when it ran it the first time it created the id of two so it just incremented from there um we have three id3 jane doe email all that cool so that's our create endpoint let's actually just add in the basic crowd stuff so next we can do async def and then get contacts so this will just list out all our contacts so our read endpoint will have the database session so we can just take um actually back in main.py let me just take this here you can say app dot get and then our just api for contacts forward slash the response model will have the list and then schemas dot and then just contact um yep so this will return a list of contacts we all have now in our get on contacts we'll say db and then we can probably just say session like that as we have it imported here just to clean it up a bit um i think as well we can do that too and then this database session we'll just copy this paste it in here just to shrink that um and that's pretty much it we just need the database session for this so we're not passing any parameters or anything in the body and then we'll just return our weight and now we just need to fill that in so inside main.py let's check this bug um yeah so if we go back to services shrink this let's create a new function async and then get all contacts this will have be a database session and this will just return a list of schemas contact and for that what we need to do is say just query the database of contact contacts equals db.query and then brackets models dot contacts and then dot all and then we can just return list and then map each of our contacts so schemas contact uh dot from orm with the contacts that we got from the database so we can now back in main.py we can call this we can say services dot get all contacts and we just need to pass in the database like so and we're getting okay maybe not maybe we can just i don't know if this is the case with default arguments that you can't really use it like that you can say oram.session and let's just take this and paste it back here click save so yeah let's just keep it as that sorry about the circles i'm leaving you guys in for this tutorial but let's head back to our end point so back into localhost let's just refresh we have this new endpoint api contacts try it out execute and we get back a list so we have john john doe and jane doe so yeah that's our list endpoint so now let's go ahead and just add in the other endpoints so the other one we want is a a detail get so api for slash contacts forward slash and then we want to specify the parameter for it so to do that all you have to do is put inside of curly brackets name so contact underscore id forward slash there the response will be a schemas dot contact and let's just do async get contact db underscore orm dot session this will actually we can just copy this whole thing here paste that there and just before that actually let's also state the contact underscore id which will be of type integer so i'm just going to pass now let that format but back inside our services let's create a new function that will get back an individual contact so we can actually let's just copy this we'll say get contact be a database session but we also want the contact id which is an integer and inside our query we can say instead of all we can filter the models.contact.id with the id that we passed in so contact id then finally we can just return in fact let's just get rid of this thing we can just return just rename that as well cool so we have our get contact now we can actually call it so return awaits and then services dot get contact the contact id equals contact id db equals db now let's head back to our api so back into the browser and let's actually try this one out we'll specify the contact id as being one execute internal server error lovely um [Music] validation errors for contact so for some reason back in get contact so we're calling um ah that's because we need to do dot first at the end of this so this get contact we've got the dot first i don't know where my head's at today but yeah now it should work fine um if we now execute it maybe it fixes it yes so we get back at john who has the id of one okay so that's how i get contact let's just add the last two which is our delete endpoint and our update so back in inside services so first we'll just start off here we'll do delete contact and it will pass in the um db session and just before that what we can do is just say contact and we'll actually pass in a contact object rather than an id because we'll also be checking to ensure that the contact exists so here we'll just say models.contact and this will not return anything but what we'll do is just say db.delete and then contact and then db.commit cool so back in main.py let's go ahead and write something useful so app.delete will copy this and point this url here we'll say just paste that in and then we'll say asynchronous function and delete and it's called contact this will have all of this in so the contact id etc and then here first of all the one thing that we want to check is first actually get a contact and see if it exists so say contact equals await and then services dot get contact will pass in the database session and also the contact id will then say if um i'm getting an error we're missing a bracket here and then if contact is none then we'll raise a http exception some fast api http exception and we'll say the status code is a 404 and the detail or the message is user does not exist cool and then finally we'll just return the or better still we can actually add that here as well so we can get contact could have done the same thing but here we'll just we'll call await and then services dot delete contact will pass in the contact that we retrieved if it does exist and the database session has db and then finally we can just say successfully deleted the user and that's about it so let's go ahead and just hit refresh from this here let's delete something so let's try it out let's delete id of once i think that's john doe execute and we get successfully to the user so now if we go back to our database we only have jane doe left and this check that i wrote in this contact await thing here we could actually add that there as well so back in our get endpoint we just post that there and yeah we can just return the contact as well i think that should work if i just go back and just retry that now in this one i think we only have three now execute and we have jane doe if i gave it a different id so something that doesn't exist we have user does not exist and the error code of 404. cool so that's our that's like our delete endpoint and also our updated um get endpoint finally let's create a update one as that's just completing our cycle of crud so we can say at app dot put and then let's just copy actually we could copy this because the response is going to be the contact and we'll say asynchronous and update contact and this will have the first of all the contact id so we'll take these two as we need the database session and the contact id and just after that we'll also need the kind of body of the request so like all the things that we need to update the data so we'll just say contact data and this will be schemas dot create contact it's been parser now and yeah missing bracket i guess why is this complaining now i think it's because we position this wrong maybe if i put it just here so yeah as that was a default argument i think we have to put that there uh but we have the contact id so the id of the contact we want to update the new data so we can update that that new that contact basically okay so first of all let's just do the whole check of um getting the contact and checking if it exists let's just copy this i put user i should actually put contact because that makes more sense let's just copy this and we'll do something similar to what we did delete okay so now that we have checked to see if the contact exists um we'll create a function inside of services and this will just update or deal with updating our contact so say async and then update contact and here we need the contact data which is of type schemas.contact or create contact the contact itself which is of type models dot contact and then finally the database session and then here we'll just return the dot contact let's put us pass um yeah so let's first say contact so the actual object in our database contact contact dot first name equals contract contact data dot first name contact dot last name equals contact data email equals contact data dot email what else do we have we have the phone number equals contact data phone number and make sure you have contact underscore data on this side and not actually using the contact otherwise it will just stay the same an error i fell into when preparing for this um but yeah so we'll say db commit so commit all the changes and then just refresh on this contact object and then finally we'll say return schemas dot contact dot from orm and then pass in the contact back in main.py we can then just say return await and then [Music] services dot update contact contact data equals contact data contact equals contact and then db equals db so yeah we check to see if our contact exists if it does exist we update that contact with the new data that's coming in with contact data if the contact does not exist then we just raise an exception cool so let's actually try this out so what do we know exists we know like the i used the contact of id3 so jane doe exists let's give that a shot if i just refresh we now have this put in yellow and if i try it out say id three we'll say that first name is um mary last name is smith email mary at gmail.com phone number we'll just give it something random let's execute it and now we get back the response which is mary smith the id has stayed the same date created to stay the same but now if we update our contacts or if we select from all our contacts in the database we now see mary smith the emails change the phone numbers changed etc so that pretty much wraps it up for this video the code for this will be available in the github repo the link is in the description i have other videos which focuses on the fast api and sql again um but also looking at foreign keys etc and it's this is the first postgres one that i've done so but yeah like the first half of this video is more focused on creating our postgres database and connecting them with fast api um if you're using sql alchemy then it's pretty much smooth sailing and pretty much the same as doing with sql light database but other than that i hope you enjoyed this video and i also apologize for the kind of backwards and forwards and some of the errors i made but uh yeah i hope you guys have a great day and i hope to see you in the next video [Music]
Info
Channel: rithmic
Views: 22,575
Rating: undefined out of 5
Keywords: FastAPI, fastapi, fastapi tutorial, fastapi python, docker, docker tutorial, docker postgres, Fastapi postgres, postgresql, postgresql tutorial, python, python tutorial, python for beginners, api, api python, api tutorial, python docker, software engineering, python programming, python projects, software developer, fastapi python tutorial
Id: 2X8B_X2c27Q
Channel Id: undefined
Length: 54min 10sec (3250 seconds)
Published: Sun Oct 31 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.