Up until now, we have seen various techniques of dealing with GET requests but this post will deal with the next operation of POST which means creating a new object or resource on the server/database. The table below gives the mapping of the HTTP request methods to CRUD operations. Let’s see how to use POST to continue building our Python API using FASTAPI
Assume we want to update the CSV file that we used in Part I of this series as the end goal. We know that to update a new row in the csv sheet we need “hostname”, “device_category”, “model”. So any update we do to our csv sheet we want to make sure we have the information we need before updating.
Let’s add a new endpoint to update the database.
@app.post("/routers/create/")
def create_device(hostname: str, device_type: str, model: str):
# Before updating the database, check if the provided hostname is already in db or not.
if not any(router['hostname'] == hostname for router in routers):
return {"response" : "DB IS UPDATED"}
else:
return {"response" : "update note needed"}
The above translates to if the request is a POST request and has hostname, device_type, model as query parameters then proceed further into evaluating if the hostname is already configured or not because we don’t want to create a new entry if it already exists.
While this method works but as you can imagine what if we are trying to update multiple records or a record contains multiple columns that we need to update. In that case, sending a huge query parameter is a problem.
Moreover, there is no validation being done if the passed parameters are actually strings or integers before updating the database. For this purpose and ease of implementation, FASTAPI leverages the power of pydantic to define the structure of the data.
class Item(BaseModel):
hostname: str
device_category: str
model: str
@app.post("/routers/create/")
def create_device(item: Item):
# Before updating the database, check if the provided hostname is already in db or not.
if not any(router['hostname'] == item.hostname for router in routers):
return {"response" : "DB IS UPDATED"}
else:
return {"response" : "update note needed"}
Let’s fill in some values and see the response we get. Please note, you can’t test this from the browser because the browser will send a GET request and we are expecting a POST request for this operation to work.
We can fill in the below values in the request body for demo purposes.
{
"hostname": "new_hostname",
"device_category": "ios",
"model": "ASR4K"
}
And this is what we get in the response body
{
"response": "DB IS UPDATED"
}
Let’s modify the code to actually update the router’s list which we can then use to update the CSV.
@app.post("/routers/create/")
def create_device(item: Item):
# Before updating the database, check if the provided hostname is already in db or not.
if not any(router['hostname'] == item.hostname for router in routers):
routers.append(item.dict())
return {"data" : routers}
else:
return {"response" : "already exists"}
Testing API once again to make sure we are getting expected results.
{
"hostname": "rtr-phil-ce01",
"device_category": "router",
"model": "ASR4k"
}
# Below is what we get in response body which means we have successfully update our database.
{
"data": [
{
"hostname": "rtr-indi-ce01",
"device_category": "router",
"model": "ISR2821"
},
{
"hostname": "rtr-usam-ce01",
"device_category": "router",
"model": "ASR1001"
},
{
"hostname": "rtr-cana-ce01",
"device_category": "router",
"model": "ISR4321"
},
{
"hostname": "rtr-phil-ce01",
"device_category": "router",
"model": "ASR4k"
}
]
}
In the request body, we could accept a list instead of the dictionary or a combination of both, and to do so all we need to do is change the pydantic data model to accept a list of strings instead of strings as key-value pairs.
In the next post we will see how to UPDATE a record in database.