Sunday, January 19, 2025

[REST API] – FLASK PYTHON #5: Viết API Update dữ liệu có trong Database

-

1. Tổng quan.

Viết API để cập nhật dữ liệu có trong cơ sở dữ liệu với Flask là một phần quan trọng của phát triển ứng dụng web.

Đây là một số lý thuyết và khái niệm quan trọng về cách thực hiện điều này:

  • HTTP Methods: Trong API, bạn sẽ sử dụng các phương thức HTTP để chỉ định loại hoạt động bạn muốn thực hiện trên dữ liệu. Các phương thức chính cho cập nhật dữ liệu bao gồm:
    • PUT: Sử dụng để cập nhật hoàn toàn một bản ghi có sẵn.
    • PATCH: Sử dụng để cập nhật một phần của bản ghi có sẵn.
    • POST: Sử dụng để tạo một bản ghi mới hoặc thực hiện một số thay đổi không rõ ràng.
  • Endpoint: Mỗi API sẽ có các điểm cuối (endpoints) riêng, là các URL đại diện cho các tài nguyên cụ thể bạn muốn cập nhật.
  • Validation: Trước khi cập nhật dữ liệu, bạn nên thực hiện kiểm tra dữ liệu đầu vào để đảm bảo tính hợp lệ và an toàn. Flask cung cấp các công cụ cho việc này.
  • Database Interaction: Bạn sẽ sử dụng ORM (Object-Relational Mapping) hoặc SQLALCHEMY để tương tác với cơ sở dữ liệu. Đảm bảo rằng bạn đang sử dụng các truy vấn thích hợp để cập nhật dữ liệu.
  • Authentication và Authorization: Bảo mật là một yếu tố quan trọng. Đảm bảo rằng chỉ người dùng được ủy quyền mới có thể thực hiện các thay đổi trong dữ liệu.
  • Error Handling: Xử lý lỗi là một phần quan trọng. Đảm bảo rằng bạn xử lý tất cả các tình huống lỗi một cách thích hợp và trả về mã lỗi thích hợp.

Dưới đây là một ví dụ đơn giản về cách viết một API để cập nhật dữ liệu trong Flask:

from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://username:password@localhost/mydatabase'
db = SQLAlchemy(app)

class Item(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    description = db.Column(db.String(255))

@app.route('/items/<int:item_id>', methods=['PUT'])
def update_item(item_id):
    item = Item.query.get(item_id)

    if item is None:
        return jsonify({'message': 'Item not found'}), 404

    data = request.get_json()
    item.name = data['name']
    item.description = data['description']

    db.session.commit()

    return jsonify({'message': 'Item updated successfully'})

if __name__ == '__main__':
    app.run(debug=True)

Trong ví dụ này, chúng ta đã xây dựng một API cho phép cập nhật thông tin của một mục cụ thể trong cơ sở dữ liệu. Chúng ta sử dụng phương thức PUT để thực hiện cập nhật. Dữ liệu đầu vào được truyền dưới dạng JSON, và chúng ta sử dụng SQLAlchemy để tương tác với cơ sở dữ liệu.

2. Thực hành.

Ở phần này chúng ta chỉ làm các file theo cây thư mục này nhé.

devnet
├── cisco_os
│   ├── __init__.py
│   ├── backend
│   │   └── arp
│   │       ├── controller.py
│   │       ├── getdata.py
│   │       └── services.py
│   ├── config.py
│   ├── extension.py
│   └── model.py
├── network.py
└── venv
    ├── db_install.sh
    └── requirements.txt
  • config.py
import os
from dotenv import load_dotenv

load_dotenv()
SECRET_KEY = os.environ.get("KEY")
SQLALCHEMY_DATABASE_URI = os.environ.get("DATABASE_URL")
SQLALCHEMY_TRACK_MODIFICATIONS = False
  • .env
KEY = "hoanghd-secret-key"
DATABASE_URL = 'mysql://hoanghd:Hoanghd164@192.168.13.200/cisco_info'
  • __init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from .backend.arp.controller import get_arp_bl
from .model import db

def create_db(app):
    with app.app_context():
        db.create_all()
        print("Created DB!")

def create_cisco_os_app(config_file="config.py"):
    cisco_os = Flask(__name__)
    cisco_os.config.from_pyfile(config_file)
    db.init_app(cisco_os)
    create_db(cisco_os)
    cisco_os.register_blueprint(get_arp_bl)

    return cisco_os
  • controller.py
from flask import Blueprint, request
import json
from .services import (add_arp_service, update_or_insert_arp_service, get_all_arp_from_device_service,
                       get_all_arp_from_db_service, get_arp_by_id_from_db_service, update_arp_entry_service)

get_arp_bl = Blueprint("get_arp_bl", __name__)

@get_arp_bl.route("/import_all_arp", methods=['GET'])
def import_all_arp():
    return update_or_insert_arp_service()

@get_arp_bl.route("/get_all_arp_from_device", methods=['GET'])
def get_all_arp_from_device():
    return get_all_arp_from_device_service()

@get_arp_bl.route("/get_all_arp_from_db", methods=['GET'])
def get_all_arp_from_db():
    return get_all_arp_from_db_service()

@get_arp_bl.route('/get_arp/<int:entry_id>', methods=["GET"])
def route_get_arp_by_id(entry_id):
    arp_data = get_arp_by_id_from_db_service(entry_id)
    if arp_data:
        return json.dumps(arp_data), 200, {'Content-Type': 'application/json'}
    else:
        return "No ARP data found with the specified ID!!!", 404

@get_arp_bl.route("/add_arp", methods=['POST'])
def add_arp():
    return add_arp_service()

@get_arp_bl.route("/update_arp_entry", methods=['PUT'])
def update_arp_entry_route():
    data = request.get_json()
    if data:
        result = update_arp_entry_service(data)
        return result
    else:
        return "Invalid data!!!", 400
  • services.py
from flask import request
from .getdata import merged_arp_data
from ...model import db, cisco_arp

def get_all_arp_from_device_service():
    arp_data = merged_arp_data()
    return arp_data

def get_all_arp_from_db_service():
    all_arp_entries = cisco_arp.query.all()
    arp_data = []
    for entry in all_arp_entries:
        arp_data.append({
            "id": entry.id,
            "address": entry.address,
            "device": entry.device,
            "interface": entry.interface,
            "mac_address": entry.mac_address,
            "ports": entry.ports
        })
    return arp_data

def get_arp_by_id_from_db_service(entry_id):
    arp_entry = cisco_arp.query.filter_by(id=entry_id).first()
    if arp_entry:
        arp_data = {
            "id": arp_entry.id,
            "address": arp_entry.address,
            "device": arp_entry.device,
            "interface": arp_entry.interface,
            "mac_address": arp_entry.mac_address,
            "ports": arp_entry.ports
        }
        return arp_data
    else:
        return None

def update_or_insert_arp_service():
    arp_data = merged_arp_data()
    for item in arp_data:
        address = item['address']
        device = item['device']
        interface = item['interface']
        mac_address = item['mac_address']
        ports = item['ports']
        existing_entry = cisco_arp.query.filter_by(address=address).first()

        if existing_entry:
            existing_entry.device = device
            existing_entry.interface = interface
            existing_entry.mac_address = mac_address
            existing_entry.ports = ports
            print("Update %s into database sussess!!!" %(address))
        else:
            new_entry = cisco_arp(address=address, device=device, interface=interface, mac_address=mac_address, ports=ports)
            db.session.add(new_entry)
            print("Add %s into database sussess!!!" %(address))
        db.session.commit()
        
    return "Add all arp into database sussess!!!"

def add_arp_service():
    try:
        address = request.json['address']
        device = request.json['device']
        interface = request.json['interface']
        mac_address = request.json['mac_address']
        ports = request.json['ports']

        existing_arp = cisco_arp.query.filter_by(address=address).first()

        if existing_arp:
            return "ARP address already exists in the database."
        else:
            new_arp = cisco_arp(address=address, device=device, interface=interface, mac_address=mac_address, ports=ports)
            db.session.add(new_arp)
            db.session.commit()

            print("Successfully added %s to the database!!!" % (address))
            return "Added successfully!!!"
    except Exception as e:
        print("Error when adding ARP:", str(e))
        return "Error when adding ARP:", str(e)

def update_arp_entry_service(data):
    address = data["address"]
    arp_entry = cisco_arp.query.filter_by(address=address).first()
    
    if arp_entry:
        if (
            arp_entry.device != data["device"]
            or arp_entry.interface != data["interface"]
            or arp_entry.mac_address != data["mac_address"]
            or arp_entry.ports != data["ports"]
        ):
            arp_entry.device = data["device"]
            arp_entry.interface = data["interface"]
            arp_entry.mac_address = data["mac_address"]
            arp_entry.ports = data["ports"]
            db.session.commit()
            return "Data updated successfully!!!"
        else:
            return "No changes in the data!!!"
    else:
        return "No data found with the given address!!!"
  • model.py
from .extension import db

class cisco_arp(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    address = db.Column(db.String(255))
    device = db.Column(db.String(255))
    interface = db.Column(db.String(255))
    mac_address = db.Column(db.String(255))
    ports = db.Column(db.String(255))

    def __init__(self, address, device, interface, mac_address, ports):
        self.address = address
        self.device = device
        self.interface = interface
        self.mac_address = mac_address
        self.ports = ports
  • extension.py
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()
  • network.py
from cisco_os import create_cisco_os_app

if __name__ == "__main__":
    cisco_network = create_cisco_os_app()
    cisco_network.run(debug=True, host='0.0.0.0', port=5000)
  • getdata.py
def merged_arp_data():
    arp_data = [
        {
            "address": "103.110.128.4",
            "device": "42.96.37.41",
            "interface": "Vlan76",
            "mac_address": "7cc2.5527.a594",
            "ports": "Po4"
        },
        {
            "address": "103.110.128.3",
            "device": "42.96.37.41",
            "interface": "Vlan76",
            "mac_address": "7cc2.5527.a8b0",
            "ports": "Po3"
        },
        {
            "address": "103.110.128.6",
            "device": "42.96.37.41",
            "interface": "Vlan76",
            "mac_address": "7cc2.5527.a974",
            "ports": "Po6"
        },
        {
            "address": "103.110.128.5",
            "device": "42.96.37.41",
            "interface": "Vlan76",
            "mac_address": "7cc2.5527.a9b4",
            "ports": "Po5"
        },
        {
            "address": "103.110.128.7",
            "device": "42.96.37.41",
            "interface": "Vlan76",
            "mac_address": "7cc2.5527.a9cc",
            "ports": "Po7"
        },
        {
            "address": "103.110.128.1",
            "device": "42.96.37.41",
            "interface": "Vlan76",
            "mac_address": "7cc2.5527.a9e8",
            "ports": "Po1"
        },
        {
            "address": "172.16.30.1",
            "device": "42.96.37.41",
            "interface": "Vlan1010",
            "mac_address": "0059.dc66.c1f5",
            "ports": "Vl1010"
        },
        {
            "address": "42.96.37.41",
            "device": "42.96.37.41",
            "interface": "Vlan214",
            "mac_address": "0059.dc66.c1fa",
            "ports": "Vl214"
        },
        {
            "address": "42.96.37.40",
            "device": "42.96.37.41",
            "interface": "Vlan214",
            "mac_address": "84eb.ef5d.461a",
            "ports": "Po100"
        },
        {
            "address": "42.96.37.43",
            "device": "42.96.37.41",
            "interface": "Vlan215",
            "mac_address": "0059.dc66.c1c8",
            "ports": "Vl215"
        },
        {
            "address": "42.96.37.42",
            "device": "42.96.37.41",
            "interface": "Vlan215",
            "mac_address": "f87a.4130.7a6a",
            "ports": "Po100"
        },
        {
            "address": "103.110.128.254",
            "device": "42.96.37.41",
            "interface": "Vlan76",
            "mac_address": "0059.dc66.c1e3",
            "ports": "Vl76"
        },
        {
            "address": "103.110.128.4",
            "device": "42.96.37.41",
            "interface": "Vlan76",
            "mac_address": "7cc2.5527.a594",
            "ports": "Po4"
        }]
    return arp_data

3. Kiểm tra kết quả.

  • Với API http://192.168.13.200:5000/update_arp_entry.

Kiếm tra lại DB.

Nếu bạn giữ nguyên data và update lại, kết quả sẽ không có data nào được update vì không có sự thay đổi.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

4,956FansLike
256FollowersFollow
223SubscribersSubscribe
spot_img

Related Stories