FastAPI 教程翻译 - 用户指南 21 - 处理错误

FastAPI 教程翻译 - 用户指南 21 - 处理错误

FastAPI Tutorial - User Guide - Handling Errors

There are many situations in where you need to notify an error to a client that is using your API.

在许多情况下,您需要将错误通知给使用 API 的客户端。

This client could be a browser with a frontend, a code from someone else, an IoT device, etc.

该客户端可以是带有前端的浏览器,来自其他人的代码,IoT 设备等。

You could need to tell the client that:

您可能需要告诉客户:

  • The client doesn’t have enough privileges for that operation.

    客户端没有足够的权限进行该操作。

  • The client doesn’t have access to that resource.

    客户端无权访问该资源。

  • The item the client was trying to access doesn’t exist.

    客户端尝试访问的项目不存在。

  • etc.

    等等

In these cases, you would normally return an HTTP status code in the range of 400 (from 400 to 499).

在这些情况下,您通常会返回 HTTP 状态码,范围为 400 到 499

This is similar to the 200 HTTP status codes (from 200 to 299). Those “200” status codes mean that somehow there was a “success” in the request.

这类似于 200 个 HTTP 状态码(从 200 到 299)。这些『200』状态码意味着请求中某种程度上存在『成功』。

The status codes in the 400 range mean that there was an error from the client.

400 范围内的状态码表示客户端出现错误。

Remember all those “404 Not Found” errors (and jokes)?

还记得所有那些『404 未找到』的错误(和笑话)吗?

Use HTTPException

使用 HTTPException

To return HTTP responses with errors to the client you use HTTPException.

要将错误的 HTTP 响应返回给客户端,请使用 HTTPException

Import HTTPException

导入 HTTPException

from fastapi import FastAPI, HTTPException

app = FastAPI()

items = {"foo": "The Foo Wrestlers"}


@app.get("/items/{item_id}")
async def read_item(item_id: str):
    if item_id not in items:
        raise HTTPException(status_code=404, detail="Item not found")
    return {"item": items[item_id]}

Raise an HTTPException in your code

在您的代码中触发 HTTPException

HTTPException is a normal Python exception with additional data relevant for APIs.

HTTPException 是一个普通的 Python 异常,带有与 API 相关的其他数据。

Because it’s a Python exception, you don’t return it, you raise it.

因为它是 Python 异常,所以您不必返回它,而是触发它。

This also means that if you are inside a utility function that you are calling inside of your path operation function, and you raise the HTTPException from inside of that utility function, it won’t run the rest of the code in the path operation function, it will terminate that request right away and send the HTTP error from the HTTPException to the client.

这也意味着,如果您在某个实用程序函数内部,在您的路径操作函数内部进行调用,从该使用程序函数内部引发了 HTTPException,则它将不会运行该路径操作函数中的其余代码,它将立即终止该请求,并将 HTTP 错误用 HTTPException 发送到客户端。

The benefit of raising an exception over returning a value will be more evident in the section about Dependencies and Security.

在依赖关系和安全性部分中,触发异常而不是返回值的好处将更加明显。

In this example, when the client request an item by an ID that doesn’t exist, raise an exception with a status code of 404:

在此示例中,当客户端通过不存在的 ID 请求项目时,触发状态码为 404 的异常:

from fastapi import FastAPI, HTTPException

app = FastAPI()

items = {"foo": "The Foo Wrestlers"}


@app.get("/items/{item_id}")
async def read_item(item_id: str):
    if item_id not in items:
        raise HTTPException(status_code=404, detail="Item not found")
    return {"item": items[item_id]}

The resulting response

结果响应

If the client requests http://example.com/items/foo (an item_id "foo"), he will receive an HTTP status code of 200, and a JSON response of:

如果客户端请求 http://example.com/items/foo (一个 item_id"foo"),则他将收到 HTTP 状态码 200 和 JSON 响应:

{
  "item": "The Foo Wrestlers"
}

But if the client requests http://example.com/items/bar (a non-existent item_id "bar"), he will receive an HTTP status code of 404 (the “not found” error), and a JSON response of:

但是,如果客户端请求 http://example.com/items/bar(一个不存在的 item_id"bar"),则他将收到 404 的 HTTP 状态码(『未找到』错误),以及以下内容的 JSON 响应:

{
  "detail": "Item not found"
}

Tip

提示

When raising an HTTPException, you can pass any value that can be converted to JSON as the parameter detail, not only str.

触发 HTTPException 时,您可以传递任何可以转换为 JSON 的值作为参数 detail,而不仅仅是 str

You could pass a dict, a list, etc.

您可以传递一个 dict,一个 list,等等。

They are handled automatically by FastAPI and converted to JSON.

它们由 FastAPI 自动处理并转换为 JSON。

Add custom headers

添加自定义 header

There are some situations in where it’s useful to be able to add custom headers to the HTTP error. For example, for some types of security.

在某些情况下,能够将自定义 header 添加到 HTTP 错误很有用。例如,对于某些类型的安全性。

You probably won’t need to use it directly in your code.

您可能不需要直接在代码中使用它。

But in case you needed it for an advanced scenario, you can add custom headers:

但是,如果您需要在高级方案中使用它,则可以添加自定义 header:

from fastapi import FastAPI, HTTPException

app = FastAPI()

items = {"foo": "The Foo Wrestlers"}


@app.get("/items-header/{item_id}")
async def read_item_header(item_id: str):
    if item_id not in items:
        raise HTTPException(
            status_code=404,
            detail="Item not found",
            headers={"X-Error": "There goes my error"},
        )
    return {"item": items[item_id]}

Install custom exception handlers

安装自定义异常处理程序

You can add custom exception handlers with the same exception utilities from Starlette.

您可以使用 来自Starlette的相同异常实用程序 添加自定义异常处理程序。

Let’s say you have a custom exception UnicornException that you (or a library you use) might raise.

假设您有一个自定义异常 UnicornException ,您(或您使用的库)可能会触发

And you want to handle this exception globally with FastAPI.

并且您想要使用 FastAPI 全局处理此异常。

You could add a custom exception handler with @app.exception_handler():

您可以使用 @app.exception_handler() 添加自定义异常处理程序:

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse


class UnicornException(Exception):
    def __init__(self, name: str):
        self.name = name


app = FastAPI()


@app.exception_handler(UnicornException)
async def unicorn_exception_handler(request: Request, exc: UnicornException):
    return JSONResponse(
        status_code=418,
        content={"message": f"Oops! {exc.name} did something. There goes a rainbow..."},
    )


@app.get("/unicorns/{name}")
async def read_unicorn(name: str):
    if name == "yolo":
        raise UnicornException(name=name)
    return {"unicorn_name": name}

Here, if you request /unicorns/yolo, the path operation will raise a UnicornException.

在这里,如果您请求 /unicorns/yolo,那么路径操作将触发 UnicornException

But it will be handled by the unicorn_exception_handler.

但是它将由 unicorn_exception_handler 处理。

So, you will receive a clean error, with an HTTP status code of 418 and a JSON content of:

因此,您将收到一个干净的错误,其 HTTP 状态码为 418 和 JSON 内容为:

{"message": "Oops! yolo did something. There goes a rainbow..."}

Technical Details

技术细节

You could also use from starlette.requests import Request and from starlette.responses import JSONResponse.

您也可以使用 from starlette.requests import Requestfrom starlette.responses import JSONResponse

FastAPI provides the same starlette.responses as fastapi.responses just as a convenience for you, the developer. But most of the available responses come directly from Starlette. The same with Request.

FastAPI 提供与 starlette.responses 相同的 fastapi.responses,只是为开发人员提供了方便。但是大多数可用的响应直接来自 Starlette。与请求相同。

Override the default exception handlers

覆盖默认的异常处理程序

FastAPI has some default exception handlers.

FastAPI 具有一些默认的异常处理程序。

These handlers are in charge or returning the default JSON responses when you raise an HTTPException and when the request has invalid data.

当您触发一个 HTTPException 且请求中包含无效数据时,这些处理程序将负责或返回默认的 JSON 响应。

You can override these exception handlers with your own.

您可以使用自己的异常处理程序覆盖它们。

Override request validation exceptions

覆盖请求验证异常

When a request contains invalid data, FastAPI internally raises a RequestValidationError.

当请求包含无效数据时,FastAPI 在内部触发一个 RequestValidationError

And it also includes a default exception handler for it.

它还包括一个默认的异常处理程序。

To override it, import the RequestValidationError and use it with @app.exception_handler(RequestValidationError) to decorate the exception handler.

要覆盖它,请导入 RequestValidationError 并将其与 @app.exception_handler(RequestValidationError) 一起使用以装饰异常处理程序。

The exception handler will receive a Request and the exception.

异常处理程序将收到一个请求和异常。

from fastapi import FastAPI, HTTPException
from fastapi.exceptions import RequestValidationError
from fastapi.responses import PlainTextResponse
from starlette.exceptions import HTTPException as StarletteHTTPException

app = FastAPI()


@app.exception_handler(StarletteHTTPException)
async def http_exception_handler(request, exc):
    return PlainTextResponse(str(exc.detail), status_code=exc.status_code)


@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
    return PlainTextResponse(str(exc), status_code=400)


@app.get("/items/{item_id}")
async def read_item(item_id: int):
    if item_id == 3:
        raise HTTPException(status_code=418, detail="Nope! I don't like 3.")
    return {"item_id": item_id}

Now, if you go to /items/foo, instead of getting the default JSON error with:

现在,如果您转到 /items/foo,而不是使用以下命令获取默认的 JSON 错误:

{
    "detail": [
        {
            "loc": [
                "path",
                "item_id"
            ],
            "msg": "value is not a valid integer",
            "type": "type_error.integer"
        }
    ]
}

you will get a text version, with:

您将获得一个文本版本,其中包含:

1 validation error
path -> item_id
  value is not a valid integer (type=type_error.integer)
RequestValidationError vs ValidationError
RequestValidationErrorValidationError

Warning

警告

These are technical details that you might skip if it’s not important for you now.

这些是技术细节,如果现在对您不重要,则可以跳过。

RequestValidationError is a sub-class of Pydantic’s ValidationError. RequestValidationError 是 Pydantic 的 ValidationError 的子类。

FastAPI uses it so that, if you use a Pydantic model in response_model, and your data has an error, you will see the error in your log.

FastAPI 使用它,因此,如果您在 response_model 中使用 Pydantic 模型,并且您的数据有错误,您将在日志中看到该错误。

But the client/user will not see it. Instead, the client will receive an “Internal Server Error” with a HTTP status code 500.

但是客户端 / 用户将看不到它。相反,客户端将收到一个 HTTP 状态码为 500 的『内部服务器错误』。

It should be this way because if you have a Pydantic ValidationError in your response or anywhere in your code (not in the client’s request), it’s actually a bug in your code.

之所以应该这样,是因为如果您的响应或代码中的任何地方(而不是客户端的请求)中有 Pydantic 的 ValidationError,则实际上是代码中的错误。

And while you fix it, your clients/users shouldn’t have access to internal information about the error, as that could expose a security vulnerability.

而且,在修复该错误时,您的客户端 / 用户不应访问有关该错误的内部信息,因为这可能会暴露一个安全漏洞。

Override the HTTPException error handler

覆盖 HTTPException 的错误处理程序

The same way, you can override the HTTPException handler.

同样,您可以覆盖 HTTPException 处理程序。

For example, you could want to return a plain text response instead of JSON for these errors:

例如,对于这些错误,您可能希望返回纯文本响应而不是 JSON:

from fastapi import FastAPI, HTTPException
from fastapi.exceptions import RequestValidationError
from fastapi.responses import PlainTextResponse
from starlette.exceptions import HTTPException as StarletteHTTPException

app = FastAPI()


@app.exception_handler(StarletteHTTPException)
async def http_exception_handler(request, exc):
    return PlainTextResponse(str(exc.detail), status_code=exc.status_code)


@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
    return PlainTextResponse(str(exc), status_code=400)


@app.get("/items/{item_id}")
async def read_item(item_id: int):
    if item_id == 3:
        raise HTTPException(status_code=418, detail="Nope! I don't like 3.")
    return {"item_id": item_id}

Technical Details

技术细节

You could also use from starlette.responses import PlainTextResponse.

您也可以使用 from starlette.responses import PlainTextResponse

FastAPI provides the same starlette.responses as fastapi.responses just as a convenience for you, the developer. But most of the available responses come directly from Starlette.

FastAPI 提供与 starlette.responses 相同的 fastapi.responses,只是为开发人员提供方便。但是大多数可用的响应直接来自 Starlette。

Use the RequestValidationError body

使用 RequestValidationError 主体

The RequestValidationError contains the body it received with invalid data.

RequestValidationError 包含接收到的主体以及无效数据。

You could use it while developing your app to log the body and debug it, return it to the user, etc.

您可以在开发应用程序时使用它来记录主体并对其进行调试,然后将其返回给用户,等等。

from fastapi import FastAPI, Request, status
from fastapi.encoders import jsonable_encoder
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from pydantic import BaseModel

app = FastAPI()


@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
    return JSONResponse(
        status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
        content=jsonable_encoder({"detail": exc.errors(), "body": exc.body}),
    )


class Item(BaseModel):
    title: str
    size: int


@app.post("/items/")
async def create_item(item: Item):
    return item

Now try sending an invalid item like:

现在尝试发送无效的项目,例如:

{
  "title": "towel",
  "size": "XL"
}

You will receive a response telling you that the data is invalid containing the received body:

您将收到一条响应,告知您包含接收到的主体的数据无效:

{
  "detail": [
    {
      "loc": [
        "body",
        "item",
        "size"
      ],
      "msg": "value is not a valid integer",
      "type": "type_error.integer"
    }
  ],
  "body": {
    "title": "towel",
    "size": "XL"
  }
}
FastAPI’s HTTPException vs Starlette’s HTTPException
FastAPI 的 HTTPException 与 Starlette 的 HTTPException

FastAPI has its own HTTPException.

FastAPI 具有自己的 HTTPException

And FastAPI’s HTTPException error class inherits from Starlette’s HTTPException error class.

FastAPIHTTPException 错误类继承自 Starlette 的 HTTPException 错误类。

The only difference, is that FastAPI’s HTTPException allows you to add headers to be included in the response.

唯一的区别是 FastAPI 的 HTTPException 允许您添加要包含在响应中的 header。

This is needed/used internally for OAuth 2.0 and some security utilities.

OAuth 2.0 和某些安全使用程序在内部需要 / 使用此功能。

So, you can keep raising FastAPI’s HTTPException as normally in your code.

因此,您可以像平常一样在代码中继续触发 FastAPIHTTPException

But when you register an exception handler, you should register it for Starlette’s HTTPException.

但是,当您注册异常处理程序时,应为 Starlette 的 HTTPException 注册它。

This way, if any part of Starlette’s internal code, or a Starlette extension or plug-in, raises a Starlette HTTPException, your handler will be able to catch and handle it.

这样,如果 Starlette 内部代码的任何部分或 Starlette 扩展或插件触发了 Starlette 的 HTTPException,则您的处理程序将能够捕获并处理它。

In this example, to be able to have both HTTPExceptions in the same code, Starlette’s exceptions is renamed to StarletteHTTPException:

在此示例中,为了能够在同一代码中同时包含两个 HTTPException,Starlette 的异常被重命名为 StarletteHTTPException

from starlette.exceptions import HTTPException as StarletteHTTPException

Re-use FastAPI’s exception handlers

重用 FastAPI 的异常处理程序

You could also just want to use the exception somehow, but then use the same default exception handlers from FastAPI.

您也可能只想以某种方式使用该异常,然后使用来自 FastAPI 的相同默认异常处理程序。

You can import and re-use the default exception handlers from fastapi.exception_handlers:

您可以从 fastapi.exception_handlers 中导入并重新使用默认的异常处理程序:

from fastapi import FastAPI, HTTPException
from fastapi.exception_handlers import (
    http_exception_handler,
    request_validation_exception_handler,
)
from fastapi.exceptions import RequestValidationError
from starlette.exceptions import HTTPException as StarletteHTTPException

app = FastAPI()


@app.exception_handler(StarletteHTTPException)
async def custom_http_exception_handler(request, exc):
    print(f"OMG! An HTTP error!: {exc}")
    return await http_exception_handler(request, exc)


@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
    print(f"OMG! The client sent invalid data!: {exc}")
    return await request_validation_exception_handler(request, exc)


@app.get("/items/{item_id}")
async def read_item(item_id: int):
    if item_id == 3:
        raise HTTPException(status_code=418, detail="Nope! I don't like 3.")
    return {"item_id": item_id}

In this example, you are just printing the error with a very expressive message.

在此示例中,您只是用非常富有表现力的消息来打印错误。

But you get the idea, you can use the exception and then just re-use the default exception handlers.

但是您知道了,可以使用异常,然后重新使用默认的异常处理程序。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
fastapi-mysql-generator 是一个用于快速生成FastAPI和MySQL的框架的工具。FastAPI是一个现代、快速(高性能)的web框架,而MySQL是一个流行的关系型数据库。 使用 fastapi-mysql-generator,可以从一个简单的命令行界面中生成 FastAPI 应用程序,并与 MySQL 数据库集成。这个工具可以自动创建数据库表和模型(Model),并提供一组 API 端点,用于执行常见的 CRUD(创建、读取、更新和删除)操作。 fastapi-mysql-generator 的主要优势之一是它的简单易用性。无论是初学者还是有经验的开发人员,都可以快速上手并生成一个完整的基于FastAPI和MySQL的应用程序。只需要几个简单的步骤,就可以生成项目的基本结构和代码。同时,fastapi-mysql-generator 还提供了一些配置选项,可以根据需求进行自定义设置,以满足特定的应用程序需求。 这个工具还提供了一些有用的特性,以增强开发的效率和便利性。例如,它可以自动生成 API 文档,包括请求和响应模型的文档说明。此外,fastapi-mysql-generator 还支持身份验证和授权功能,以确保 API 路由的安全性。 总而言之,fastapi-mysql-generator 是一个快速生成 FastAPI 和 MySQL 应用程序的方便工具。它简化了应用程序的开发过程,并提供了一些有用的特性,以提高开发效率和便利性。无论是初学者还是有经验的开发人员,都可以受益于这个工具的使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值