Skip to content

Network Automation

My journey with Network & Cloud Automation

Menu
  • Beginner
  • DevOps-NetDevOps
  • Network Automation
    • Docker
    • Python Libraries
      • NAPALM
      • Netmiko
      • Jinja2
      • Scrapli
      • Yang
  • Cloud Automation
    • Terraform
  • Python 🐍 Tips and Tricks
Menu
fastapi_5

Python API Using FASTAPI – UPDATE – PUT – PATCH – Part V

Posted on November 15, 2021November 5, 2021 by Gurpreet Kochar

To continue our journey to build a python API using FASTAPI, we will see how to update a record in the database either fully or partially. These operations are called PUT or PATCH. The fundamental difference between a PUT and PATCH operation is that PUT indicates updating the entire record while PATCH means updating a part of the record.

For example, In each record, we have hostname, device_category, model. If we want to update all the key values of a record, it’s called PUT whereas if we only want to update specific fields while still keeping the remaining fields the same, it’s called a PATCH operation. However, this doesn’t mean that we can’t make partial updates using PUT.

Let’s take a look at the PUT operation and some use cases. Suppose we want to update the model number of a specific hostname.

@app.put("/update_router/", tags=["routers"])
# at the time of creating all fields are mandatory but at the time of updating the record
# all fields are not mandatory.
# if we are updating just one field of the entire record, other fields should remain same
def update_router(device_model: UpdateDevice):
    if any(device["hostname"] == device_model.hostname for device in devices):
        for device in devices:
            if device["hostname"] == device_model.hostname:
                device.update(device_model.dict())
        return {"data": devices}
    else:
        return {"response": "not found"}

The above code is checking if the hostname provided in the request body of the PUT request exists in the database or not. If it exists, the database will be updated with the hostname, device_category, and model fields from the values that were passed in the body of the request.

We can make the body parameters optional or mandatory but the problem is if you make fields options and only hostname is mandatory, then your database may have blank values because you could potentially update a hostname record without the need of providing other values.

If you don’t make fields optional, then even if you just need to update the hostname, you will have to supply other remaining values of the record manually which is a lot of work and highly inconvenient.

So we need to have a way that will allow changes to be made against the parameter that has been supplied in the body parameter while others remain the same and have no modifications done to them.

First of all, instead of using Device as the model, we will create another Pydantic device model named UpdateDevice with optional fields instead.

class UpdateDevice(BaseDevice):
    hostname: str
    device_category: Optional[str] = None
    model: Optional[str] = None

Now we want to build a logic that the field values should only be modified when the user-provided input values are not null.

@router.put("/update_router/", tags=["routers"])
def update_router(device_model: UpdateDevice):
    for device in devices:
        if device["hostname"] == device_model.hostname:
            for k, v in device_model.dict().items():
                if v:
                    device[k] = device_model.dict()[k]
            return {"data": device}
    return {"response": "not found"}

This is just one way, if you have another way, please leave a comment.

As with most of the things in python, it can always be made easier. Code above is no exception.

Let’s see the pydantic way of doing things.

@router.put("/update_router/", tags=["routers"])
def update_router(device_model: UpdateDevice):
    for device in devices:
        if device["hostname"] == device_model.hostname:
            device.update(device_model.dict(exclude_unset=True))
            return {"data": device}
    return {"response": "not found"}

exclude_unset=True, this tells fastapi to ignore all the fields that are not passed which are automatically set to Null. Pydantic offers multiple methods to get around these problems. Read more here

https://pydantic-docs.helpmanual.io/usage/exporting_models/#modeldict

exclude_unset: whether fields that were not explicitly set when creating the model should be excluded from the returned dictionary; default False

exclude_defaults: whether fields which are equal to their default values (whether set or otherwise) should be excluded from the returned dictionary; default False

exclude_none: whether fields which are equal to None should be excluded from the returned dictionary; default False

Instead of calling the above as a put operation, we could have also called it a patch and it behaves exactly the same

@router.patch("/update_router/", tags=["routers"])
def update_router(device_model: UpdateDevice):
    for device in devices:
        if device["hostname"] == device_model.hostname:
            device.update(device_model.dict(exclude_unset=True))
            return {"data": device}
    return {"response": "not found"}

Now that we have basics aside, we can focus on a little more advanced topics like properly structuring a fastapi project or how to use certain features of pydantic with fastapi to make our project more robust and easier to manage.

Know someone who may benefit? Share this:

  • Tweet
  • Click to share on Telegram (Opens in new window) Telegram
  • Click to share on WhatsApp (Opens in new window) WhatsApp
  • Click to email a link to a friend (Opens in new window) Email
  • More
  • Click to print (Opens in new window) Print
  • Click to share on Reddit (Opens in new window) Reddit
  • Share on Tumblr
  • Pocket

Like this:

Like Loading...

Related

1 thought on “Python API Using FASTAPI – UPDATE – PUT – PATCH – Part V”

  1. asdfasdf says:
    May 31, 2023 at 2:48 AM

    tf is “devices” defined/importd/whatever?

    Loading...
    Reply

Leave a Reply to asdfasdfCancel reply

All Blog Posts
My Resume

Upcoming Posts

Sorry - nothing planned yet!

Recent Posts

  • How to backup configuration to TFTP Server using Ansible – Part II
  • How to backup network devices using Ansible – Part I
  • Netmiko SSH Proxy/JumpServer
  • A short note on SASE
  • Understanding Ansible

Recent Comments

  1. Jack on Multithreading with Python for Network Engineers
  2. LifeCanvas on [Theory] Multithreading vs Multiprocessing vs AsyncIO
  3. Jasper Horng on Netmiko SSH Proxy/JumpServer
  4. asdfasdf on Python API Using FASTAPI – UPDATE – PUT – PATCH – Part V
  5. Gurpreet Kochar on Python Scrapli AsyncIO Usage

Archives

  • September 2022
  • February 2022
  • January 2022
  • December 2021
  • November 2021
  • October 2021
  • September 2021
  • August 2021
  • July 2021
Topic Request / Suggestion
Loading
© 2025 Network Automation | Powered by Minimalist Blog WordPress Theme
%d