Skip to main content

Specify contracts for FastAPI endpoints.

Project description

Test on push to main Test coverage PyPI - version PyPI - Python Version

FastAPI-icontract is a FastAPI extension for design-by-contract which leverages icontract to allow you to specify and enforce code contracts in your FastAPI endpoints.

Depending on how you set it up, FastAPI-icontract will:

  • automatically enforce the contracts during testing or in production,

  • automatically add the contracts to your OpenAPI specification, and

  • render the Swagger UI with a specialized contracts plugin for nicer visualization.

Benefits of Adding Contracts to Your API

Enforcing code contracts in your FastAPI development opens up new venues for approaches to more systematic design at the API level:

  • Contracts are an important part of the specification.

    Unlike human language, contracts written in code are unambiguous.

  • Contracts are automatically verifiable.

    Your clients can rest assured that you actually run them. FastAPI-icontract will specify precisely which contracts are run in production and which were only verified during testing.

  • Contracts provide deeper testing.

    If you have a mesh of microservices that you need to test in conjunction, turn on all the contracts and test against your client’s data instead of your own limited unit test data.

  • Contracts specified in code allow for automatic client-side verification.

    Thus you can signal formally to the client up-front what you expect (using pre-conditions), while the client can verify what to expect back from you (using post-conditions).

  • Contracts are not just for input validation.

    Though you can use contracts for input validation as well, FastAPI already allows you to specify how you want your input verified. Contracts, on the other hand, really shine when you want to specify relations between the endpoints.

  • Contracts allow for automatic test generation.

    Tools for property-based testing such as Schemathesis can automatically generate test data and verify that your API works as expected. Post-conditions are an easy way to define your properties to be tested.

    There is an ongoing discussion with the authors of the Schemathesis how to integrate it with tools which generate data based on contracts such as icontract-hypothesis.

  • Contracts open up a wider ecosystem for analysis.

    When you decorate the endpoints with contracts, you can immediately use analysis tools such as CrossHair to analyze your code and find bugs.

    (Though this only makes sense for really stateless, purely functional endpoints.)

Teaser

The full documentation is available at: fastapi-icontract.readthedocs.io.

The following example is meant to invite you to further explore the extension.

from typing import Optional

from fastapi import FastAPI
from pydantic import BaseModel
from icontract import SLOW
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("/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")
@fastapi_icontract.snapshot(lambda book: has_book(book.identifier), name="has_book")
@fastapi_icontract.snapshot(lambda: book_count(), name="book_count")
@fastapi_icontract.ensure(lambda book: has_book(book.identifier))
@fastapi_icontract.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)

Versioning

We follow Semantic Versioning. The version X.Y.Z indicates:

  • X is the major version (backward-incompatible),

  • Y is the minor version (backward-compatible), and

  • Z is the patch version (backward-compatible bug fix).

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastapi-icontract-0.0.3.tar.gz (13.1 kB view details)

Uploaded Source

File details

Details for the file fastapi-icontract-0.0.3.tar.gz.

File metadata

  • Download URL: fastapi-icontract-0.0.3.tar.gz
  • Upload date:
  • Size: 13.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.7.1 importlib_metadata/4.10.1 pkginfo/1.8.2 requests/2.27.1 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.10.2

File hashes

Hashes for fastapi-icontract-0.0.3.tar.gz
Algorithm Hash digest
SHA256 e793c3a6c8ba2b8fc7536134ddce809f70cc136842780bfdf88880a23fac2538
MD5 52dc96957dce44be61d22106079238d6
BLAKE2b-256 f10aa1aeb22d29ced2ffa15c153dd195ab8a649a7904d1da822cdce1b9b91093

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page