跳转到主要内容

为FastAPI端点指定合约。

项目描述

Continuous integration Test coverage PyPI - version PyPI - Python Version

FastAPI-icontract是一个FastAPI扩展,用于设计-by-contract,它利用icontract允许你在FastAPI端点中指定和执行代码合约。

根据您的设置,FastAPI-icontract将

  • 自动在测试或生产过程中执行合约,

  • 自动将合约添加到您的OpenAPI规范

  • 并通过专门的合约插件渲染Swagger UI,以便更好地可视化。

添加合约到API的好处

在FastAPI开发中执行代码合约为API级别的更系统化设计提供了新的途径

  • 合约是规范的重要组成部分。

    与人类语言不同,用代码编写的合约是明确的。

  • 合约是自动可验证的

    您的客户可以放心,您实际上运行了它们。FastAPI-icontract将指定生产中运行的合约以及仅在测试期间验证的合约。

  • 合约提供了更深入的测试。

    如果您需要测试相互连接的微服务网格,请开启所有合约并针对客户的数据进行测试,而不是使用您自己的有限的单元测试数据。

  • 代码中指定的合约允许进行自动的客户端验证。

    因此,您可以提前正式地向客户端发出信号,告知您期望什么(使用先决条件),而客户端可以验证从您那里期望得到什么(使用后置条件)。

  • 合约不仅仅是用于输入验证。

    尽管您也可以使用合约进行输入验证,但FastAPI已经允许您指定您想要如何验证输入(请参阅链接)。另一方面,当您想要指定端点之间的关联时,合约才能真正发挥其优势。

  • 合约允许自动生成测试。

    例如,Schemathesis这样的基于属性的测试工具可以自动生成测试数据,并验证您的API是否按预期工作。后置条件是定义要测试的属性的一种简单方法。

    我们正在与Schemathesis的作者讨论如何将其与基于合约生成数据的工具(如icontract-hypothesis)集成。

  • 合约为分析开辟了一个更广泛的生态系统。

    当您用合约装饰端点时,您可以直接使用分析工具,如CrossHair来分析您的代码并查找错误。

    (但这仅适用于真正无状态的、纯函数式的端点。)

预告

完整文档可在以下地址找到: fastapi-icontract.readthedocs.io

以下示例旨在邀请您进一步探索此扩展。

from typing import Optional, List, Any

from fastapi import FastAPI
from pydantic import BaseModel
import asyncstdlib as a

from fastapi_icontract import (
    require, snapshot, ensure,
    wrap_openapi_with_contracts,
    set_up_route_for_docs_with_contracts_plugin
)

app = FastAPI()

@app.get("/has_author", response_model=bool)
async def has_author(identifier: str):
    """Check if the author exists in the database."""
    ...

@app.get("/categories", response_model=List[str])
async def get_categories():
    """Retrieve the list of available categories."""
    ...

class Book(BaseModel):
    identifier: str
    author: str

@app.get("/has_category", response_model=bool)
async def has_category(identifier: str):
    """Check if the author exists in the database."""
    ...

@app.get("/books_in_category", response_model=List[Book])
@require(
    has_category, status_code=404, description="The category must exist."
)
@ensure(
    lambda result: a.all(a.await_each(has_author(book.author) for book in result)),
    description="One ore more authors of the resulting books do not exist."
)
async def books_in_category(category: str) -> Any:
    """Retrieve the books of the given category from the database."""
    ...

@app.get("/has_book", response_model=bool)
async def has_book(book_id: str) -> Any:
    """Check whether the book exists."""
    ...

@app.get("/book_count", response_model=int)
async def book_count() -> Any:
    """Count the available books."""
    ...

@app.post("/upsert_book")
@snapshot(lambda book: has_book(book.identifier), name="has_book")
@snapshot(lambda: book_count(), name="book_count")
@ensure(lambda book: has_book(book.identifier))
@ensure(
    lambda book, OLD: a.apply(
        lambda a_book_count: (
                OLD.book_count + 1 == a_book_count if not OLD.has_book
                else OLD.book_count == a_book_count),
        book_count()))
async def add_book(book: Book) -> None:
    ...

# Include contracts in /openapi.json
wrap_openapi_with_contracts(app=app)

# Include swagger-ui-plugin-contracts in /doc
set_up_route_for_docs_with_contracts_plugin(app=app)

版本控制

我们遵循语义版本控制。版本X.Y.Z表示

  • X是主版本(不向后兼容),

  • Y是次要版本(向后兼容),

  • Z是补丁版本(向后兼容的 bug 修复)。

项目详情


下载文件

下载适用于您平台的应用程序。如果您不确定选择哪个,请了解更多关于安装包的信息。

源代码分发

fastapi-icontract-0.0.4.tar.gz (16.1 kB 查看哈希值

上传时间 源代码

支持者

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面