FastAPI - Request Body and POST requests | Pydantic pre-validators

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
let's continue our exploration of fast API and look at how to handle the request body that's submitted in a post request and this is a very common use case our apis often need to create new resources on the back end and then store those in a database so let's see how to use fast API to create an endpoint that takes a post request and also how to integrate the data coming into that endpoint with pantic let's get started now I've got a page here open on the fast API documentation for the request body I'm going to link this below the video and let's have a very quick look at what it says here when you need to send data from a client and let's say that's coming from a browser to your API you will send that as a request body and that body can be something like Json data or it could be form data fast API will allow you to handle both of those types of incoming data so you have the distinction here of a request body which is sent from the client to our fast API server and then also our response body and that's the data that's sent back to the client from the endpoint now to declare our request body we're going to use pantic models so let's get started now if we look at the application we've been building we have the schemas dopy file and you can see that we have two models here we have an album model and we have the band model and the band is the parent in that relationship a band will consist of zero or more albums now our client might want to create a new band in the database so we need to allow them to do that via a post request and create an end point for that now we're going to refactor the schemas that we have here because when we send a post request we're not going to send the ID for the new band that's something that's going to be determined on the back end typically by the database and we'll see that later on when we integrate fast API with a database but what we're going to do is we're actually going to refactor the schemas dop file to start with so instead of a band model I'm going to create a band base model and that's going to inherit from the base model and that's going to contain all of the common fields that we need in the model so we're going to get rid of the ID here we're going to keep the name the genre and the albums and then we're going to create two more classes below that the first one is going to be a band create model and this one is going to inherit from the band base that we've got above here so this base model here you can think of that as almost like an abstract class it contains the common fields and we're never going to create this in the application but we are going to reference the subclasses of that so we're going to create this V create class that inherits from that and we don't need any more Fields here so we're just going to pass on that and then we can create another class below that with the name band with ID and actually I'm going to capitalize ID here and again that's going to inherit from band base and this time we Define an extra field the ID field which is going to be an integer so now instead of a single model with all of the fields we have three models and this allows us to get a bit more flexible with the data schema and we don't need to pack everything into a single model now we need to go back to main. Pi and we need to refactor this so from schemas we're going to import all all of these band base band create and bandwidth ID now before we go on here if you're wondering where this pattern comes from I'm going to link to this GitHub repository below the video this is created by the guy that made fast API and it's kind of an example full stack application that uses fast API and post Griz now you can see we have some pantic models here we have a user base model that contains the shared properties that are going to be inherited by all of the other classes and then we have a user create model that inherits from that model and defines the extra fields that are needed on the creation of a new user and also it has that ID field at the bottom here and it also contains some other models that have the ID field as well so this kind of Base Class model here that can contain the shared properties and that's exactly what we've done with our very simple band based schema and then we Define the classes that inherit from that now back to main. Pi let's refactor this we have an end point that's returning all of the Bands so instead of band here we're going to return band with ID and we need to change all of the references here and similarly for the end point containing the single Band by its ID we need to return that band with an ID and refactor all of those references again now we have another endpoint here we don't need to touch that one what we're going to do now is we're going to define a new endpoint and that's going to take this app object but instead of a get request it's going to be a post request so let's go to the bottom of the file and we're going to define a new decorator here and it's going to be app. poost now the end point is going to be/ bands and this is the same path that we have in the band list page here but instead of a get request it's a post request so when the user or when the client sends a post request it's going to hit the function that we're about to Define here so let's create a function async diff create band and that is going to take the request body as a parameter so let's call the request body band data and we're going to give it a type here of that band create model so what we're saying here is that we expect the client to send the data that conforms to that model band create so if we look at that model that just inherits from band base and doesn't Define any more Fields so we expect the client to send the name the genre and optionally some albums and if they don't send any albums it's going to default to the empty list so in order to type in the request body that's coming from the client we can just Define that parameter in our Handler function and give it the correct pantic type and then pantic and fast API is smart enough to actually extract that from the request body and create the model for us for our use in this function now interestingly when we actually create the band what we're going to return is we're going to return the band with the ID so we're going to generate the ID in this function and then return the entire band with ID model that contains not only the fields that have been submitted from the client but also the autogenerated ID so let's get started with writing the logic of this function we're going to get the ID simply by looking at this hardcoded list we're going to get the last element and increment that by one so let's create an ID here it's going to be bands and then we're going to index in at the very end of that list that will give us the dictionary representing that band and we can then get the ID from that and add one what we can then do is we can create a band here and what we're going to do in order to do that is we're going to create a band with ID object and that can contain our autogenerated ID and then we can dump the properties of the band data model that's been passed in and we can call the model dump function there in order to convert that to a dictionary and pass the results keys and values into the band with ID so when we create the band with the ID we just pass the ID in and then we pass in all of the properties that have been sent from the client and verified and validated by pantic in order to create this model that we've called band data now we need to convert the band with ID to a python dictionary and then append it to this list here if we look at the bands list that we have these are all dictionaries at the moment so what we're going to do is we're going to actually call do model dump on the resulting band with with ID model that's going to give us back the dictionary and we can then append that to our hardcoded list of bands now don't worry later on this is all going to get cleaned up and we're going to use a database in order to generate these IDs and we're not going to have to worry about converting everything to dictionaries and so on and the final thing to do here is just return the band that we have this is a dictionary after we call model dump but when we return that dictionary it's going to convert that to adjacent and validate the schema based on the band with ID model and that's the type hint for this return statement in the function now we're going to test this out now and in order to do that I'm going to install an extension on vs code so there's an extension that allows you to perform API requests in vs code and it's called rest client so let's install that just now and as this says here RIS client will allow you to send HTTP requests and view the response in Visual Studio code directly so let's go back to our file here our main.py file and actually on the left hand side we're going to create a new file and I'm going to call this a api. HTTP now if we give the file that we create here a HTTP extension we can then use that file with the rest client and within this file all we need to do is Define our HTTP request so we're going to send a post request in order to test this and it's going to be to Local Host 8000 SL bans and this endpoint will then send the request to this function here because it's a post request and it matches the root that we have here now as well as the end point we also want to give it a bit more information we're going to say that we're going to send Json data and then we can Define the body of that data so I'm going to add some data here we're going to give the band a name of Boards of Canada and a genre of electronic now how do we send the request with this client I'm going to get rid of the sidebar and you can see just above where we Define the API request there is this text here that says send request this is defined by the rest client if we click that we're going to be able to send the request but of course before we do that we need to actually start the server so at the bottom here I have have the virtual environment with fast API installed we're going to run uicorn main app and we can pass-- reload into that that's going to start the server on Port 8000 and you can see in our API function that's the port that we're using we can then test this out so we're going to hit send request here and we get back the data for our new band and you can see it contains the newly generated ID for that band and all of the data that we actually sent is being sent back to us here as well so that post request should have added the new band to our lists we're going to Define another request here so we can put three of these hashes and then we can define a get request and again it's going to be to Local Host 8000b so when we send a get request here it's going to return the list of all of the Bands so let's hit send request and we get back this list and it contains the new band that we just added so that is all working fine of course later on when we send the post request it's going to send that data into the database but for now this is exactly what we want and we can amend this get request we could add a query parameter from the last video so for example we can limit this to only bands with the genre of electronic when we send that request we only get back two records now Apex Twin and Boards of Canada which is the new band now one final thing to show at the moment is that when we send the post request at the top here we can also optionally send some albums so I'm going to add an albums key to the post data in this request body and I'm going to send a list of albums from Boards of Canada tomorrow's Harvest and this one here music has the right to children so we're sending the albums along with the new band and we're sending two of those so let's save api. HTTP and let's send this request and this time we get back the band with the ID of six and it contains some albums this time so we can actually create the albums in place when we send that post data and the reason for that if we close this and go back to schemas dopy our band create model inherits from band base and the band base model contains these albums and that's a list of album models we have the album model model above here so because this band create model is the one that actually validates the data in the post request we can actually send these albums in that request let's now move on and we're going to look at the API documentation that we have for this new post endpoint so let's go back to the browser and we're going to look at the API documentation and you can see the docs for our new endpoint this time it's got the method of post and you can see some metadata here it's got uh the title of create band and that title is coming from the actual name that we give to the function and if we inspect the documentation for this we can see the example schema for the request body because we've used that band create pantic model the request body that the post request is expecting now has that structure and that is very useful for the clients that want to send new data to our API they know the exact structure of that data now because of the pantic model and if we scroll down we can see the response schema and this time it contains the I ID as well as the other fields that we had above and again that's because we've typ hinted the return type from this fast API Handler function as the band with ID pantic model so again everything we're doing here with these pantic models is very well integrated into the API documentation that's provided by fast API and this is all out of the box with no configuration it's very useful when you're developing with fast API so let's finish this video with an example of how we might limit the genre that we're sending here rather than accept any string we might want to limit that to a predefined list of genres so let's go back to our application we're going to go to schemes. Pi now we had this at the top genre URL choices and this was for the URL query parameters and these are lowercase by default what we're going to do is basically just replicate this so I'm going to copy this and I'm going to paste it just below and we're going to call this one genre choices and I'm going to uppercase these and I'll show you why in a second we're going to make them title case basically and the reason for that is that these should match what we have in the data that we have in the hardcoded list so in the list we have the genre of music and that starts with a capital letter and it also has this for hip-hop so it's title case so we're going to use this new genra choices enum so let's copy that we're going to use it in this band base model here that we are inheriting from below here we're going to use that to limit the genres that can be passed into the API now just before we go on I know this is kind of like repetition of code there are different ways of doing this but as long as you name things very clearly this is obviously for the URL choices and the query parameters and this one here is just the generic choices that we want to use in the hardcoded list or in the database that we're using behind the scenes so we're going to use genre choices and what we're going to do is reference that in the base model so we don't need to Define that twice it's in the base model and it's going to limit the possible genres to one of those that are defined in the enum so let's see what effect this has having on our API if we go back to api. http and go down to this get request if we send that request you can see we are getting an internal server error and this is telling us that the genre choices object has no attribute lower so let's go back to main. Pi and it's line 25 I'm going to close this on the right hand side so line 25 here and the problem here is that the genre is now a field on the enum so we can get the value of that by referencing value and we can then save that and go back to API HTTP and resend that request and we get back the data this time now what's the benefit of using this enum here to limit the genres let's go back to api. http and what I'm going to do at the top here I'm just going to remove these albums for Simplicity and we're going to define the genre as electronic and send this request again and we get back the new record with the ID of five and that works because electronic is a valid genre now if we Define that to something such as Jazz that's not defined in that enum we're going to to get back an error here that the input is not being recognized so this is very useful if you want to limit the data for a particular field that's being sent in a post request and that can help you keep your database clean and stop your database being filled with random values so it can be useful to Define these enums for that now one thing to note here if we go back to the data that's being sent in this request body I can go back to electronic but if I make that all lowercase and we save this when we send that request we're getting back the same error and this is going to be the same if we send it in all uppercase if we send that again it's the same problem because we have the enum the genre is only going to work with the value that we Define here so it's going to only work with the title case now that's a problem maybe the client will send data in lower case or upper case what we want to do is actually convert that to title case how can we do that what we can do to solve this is Define what's called a pre validator in pantic so I'm going to scroll down to the band create model that we have here and this at the moment it just in inherits from band base and it doesn't do anything else we're going to get rid of that pass statement and we're going to add a validator here and the validator is going to convert the value for the genre that's being passed in to title case before the validations are run now in order to do that at the top from pantic we're going to import the validator function and we can then go down to the band create model and we're going to Define that validator using a validator decorator and we pass the field that we want to validate against and that's the genre field and in order to make this a pre validator that's run before the normal validations we can pass pre equals true and this is very useful for performing any kind of transformation of data before the normal validation is run and that can help you in circumstances like this so let's define the function it's going to be called title case genre and a validator function in pantic is a class method it takes the class and the value that's actually been passed in to the pantic model and what we're going to do is simply return the value but we're going to return it in title case and as an example of what that's going to do it's going to convert the value of rock imagine that had all lowercase characters it's going to convert that to this and that would do the same if it was all uppercase or even if it was a mixture of characters the end result after calling the title function is going to be this output here so let's remove this comment and save this file and we're going to try this again in our api. HTTP file so let's send the request and this time we're sending the genre with all uppercase characters so let's send that and instead of the error we're now getting back the new record it has the ID of five and if we look at the genre you can see it's been converted to title case and this will also work if we copy the lower case into this and send the request again every time we do that it's converted to title case so thank you for watching this video if you've enjoyed the video please like And subscribe to the channel and again any suggestions for this pantic course as we build up to more complex topics please leave them in the comments thanks again and we'll see you in the next value
Info
Channel: BugBytes
Views: 4,365
Rating: undefined out of 5
Keywords:
Id: zq0_g3BKltE
Channel Id: undefined
Length: 18min 4sec (1084 seconds)
Published: Fri Dec 15 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.