14 FastAPI自定义异常

在开发现代 Web 应用时,异常处理是保证系统稳定性和良好用户体验的重要部分。FastAPI 提供了强大的异常处理机制,允许开发者不仅使用内置的异常类型,还可以根据业务需求自定义异常类型、响应格式和错误处理逻辑。本文将深入探讨如何在 FastAPI 中自定义异常,并捕获常见的数据库错误和业务逻辑错误。

1. 为什么要自定义异常?

在很多场景下,应用程序可能会抛出一些特定的错误,如数据库查询失败、文件操作错误等。通过自定义异常,我们可以:

  • 让错误响应的格式更加符合业务需求。
  • 提供更友好的错误信息,帮助开发者和终端用户快速定位问题。
  • 使得错误处理更加统一和可维护。

FastAPI 提供了高度可定制的异常处理机制,我们可以利用这一点来构建自己的异常类型,并在应用中统一处理各种错误。

2. 如何自定义异常类型和响应格式

2.1 自定义异常类型

在 FastAPI 中,可以通过继承 Exception 基类或 HTTPException 来创建自定义异常。我们可以为这些异常设置更多的属性,以便在异常发生时能够返回更多的信息。

2.1.1 自定义异常类

例如,我们可以定义一个 ItemNotFoundError 异常,当某个商品在数据库中不存在时抛出这个异常。

class ItemNotFoundError(Exception):
    def __init__(self, item_id: int):
        self.item_id = item_id
        self.message = f"Item with ID {item_id} not found"
        super().__init__(self.message)

在这个例子中,ItemNotFoundError 异常接受一个 item_id 参数,并返回一个带有详细错误信息的异常。

2.1.2 自定义 HTTP 异常响应格式

自定义异常类后,我们可以通过异常处理器来捕获这些异常,并根据需要定制错误响应的格式。例如,可以为 ItemNotFoundError 定义一个异常处理器:

from fastapi import FastAPI, HTTPException
from fastapi.responses import JSONResponse
from fastapi.exception_handlers import exception_handler

app = FastAPI()

@app.exception_handler(ItemNotFoundError)
async def item_not_found_exception_handler(request, exc: ItemNotFoundError):
    return JSONResponse(
        status_code=404,
        content={"message": exc.message, "item_id": exc.item_id},
    )

在这个处理器中,我们捕获 ItemNotFoundError 异常,并返回一个包含错误信息和 item_id 的 JSON 响应。

2.2 捕获数据库错误

在 FastAPI 应用中,数据库操作是常见的错误来源。常见的数据库错误包括连接失败、查询错误或数据唯一性约束违规等。通过自定义异常,我们可以为这些数据库错误提供清晰的响应。

例如,我们使用 SQLAlchemy 作为 ORM 来操作数据库,捕获 SQLAlchemyError 异常并返回自定义错误响应。

2.2.1 捕获数据库连接错误

假设在数据库连接过程中发生了错误,我们可以定义一个 DatabaseConnectionError 异常:

from sqlalchemy.exc import SQLAlchemyError
from fastapi import HTTPException

class DatabaseConnectionError(Exception):
    def __init__(self, message: str = "Database connection failed"):
        self.message = message
        super().__init__(self.message)

然后,我们可以在数据库操作的代码中捕获这个错误,并返回适当的 HTTP 错误响应:

from fastapi import HTTPException
from sqlalchemy.exc import SQLAlchemyError

@app.get("/items/{item_id}")
async def get_item(item_id: int):
    try:
        item = db.query(Item).filter(Item.id == item_id).first()
        if item is None:
            raise ItemNotFoundError(item_id)
        return item
    except SQLAlchemyError:
        raise DatabaseConnectionError("Unable to connect to the database")

在这个例子中,我们捕获了 SQLAlchemyError 异常,并抛出一个自定义的 DatabaseConnectionError,返回给客户端一个 500 错误,并附带描述数据库连接失败的详细信息。

2.2.2 捕获数据库约束错误

对于数据库中的唯一性约束或其他约束失败错误,可以创建专门的异常来处理。例如,创建一个 UniqueConstraintError 用于处理违反唯一性约束的情况:

from sqlalchemy.exc import IntegrityError

class UniqueConstraintError(Exception):
    def __init__(self, message: str = "Unique constraint violated"):
        self.message = message
        super().__init__(self.message)

当捕获到 IntegrityError 时,我们就可以抛出这个异常并返回自定义的错误响应:

@app.post("/items/")
async def create_item(item: Item):
    try:
        db.add(item)
        db.commit()
        return item
    except IntegrityError:
        raise UniqueConstraintError("Item with this name already exists")

在这个例子中,如果插入重复的商品名称导致唯一性约束违规,就会抛出 UniqueConstraintError 异常,返回 400 错误并附带详细的错误信息。

3. 捕获和处理业务逻辑错误

在一些业务场景下,应用程序可能需要根据复杂的业务规则做出判断。业务逻辑错误通常并不涉及技术层面的异常(如数据库错误),而是与应用程序的特定需求相关。例如,订单金额不足、用户权限不足等。

3.1 自定义业务逻辑错误

假设我们在处理支付请求时需要确保余额足够,如果余额不足,则抛出一个 InsufficientFundsError 异常:

class InsufficientFundsError(Exception):
    def __init__(self, balance: float, required: float):
        self.balance = balance
        self.required = required
        self.message = f"Insufficient funds: Available {balance}, Required {required}"
        super().__init__(self.message)

然后,我们可以在支付处理函数中捕获并处理这个异常:

@app.post("/pay/{user_id}")
async def make_payment(user_id: int, amount: float):
    user = db.query(User).filter(User.id == user_id).first()
    if user.balance < amount:
        raise InsufficientFundsError(user.balance, amount)
    
    user.balance -= amount
    db.commit()
    return {"message": "Payment successful", "new_balance": user.balance}

如果用户的账户余额不足,系统将抛出 InsufficientFundsError 异常,返回一个详细的错误信息,提醒用户余额不足。

3.2 定制错误响应格式

同样地,我们可以通过 FastAPI 的异常处理器来定制业务逻辑错误的响应格式:

@app.exception_handler(InsufficientFundsError)
async def insufficient_funds_exception_handler(request, exc: InsufficientFundsError):
    return JSONResponse(
        status_code=400,
        content={"message": exc.message, "balance": exc.balance, "required": exc.required},
    )

在上面的代码中,我们创建了一个 insufficient_funds_exception_handler,捕获 InsufficientFundsError 异常,并返回包含余额信息和错误描述的 400 错误响应。

自定义异常处理是构建健壮、易维护应用程序的重要部分。通过在 FastAPI 中创建自定义异常类型,我们可以:

  • 捕获并处理特定类型的错误,如数据库错误、业务逻辑错误等。
  • 提供更加友好和可读的错误响应,帮助开发者和终端用户理解问题。
  • 统一异常响应格式,减少重复代码,并提高系统的可维护性。

在本文中,我们介绍了如何自定义异常类型、如何捕获和处理数据库错误及业务逻辑错误,并通过异常处理器定制错误响应。通过这些技术,开发者可以在 FastAPI 应用中实现更高效、灵活的错误管理。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值