Post-conditions

The post-conditions are the conditions which must hold after the execution of the endpoint.

You specify the post-conditions using the decorator ensure.

Post-conditions usually involve comparing the state before and after the request to an endpoint. The state after the request is directly available to the post-condition.

Snapshots

However, you need to specifically instruct fastapi-icontract which state needs to be capture before the request. This is done by using snapshots with the decorator snapshot.

Examples

Here is a simple snippet that involves only a post-condition (see the full example):

import asyncstdlib as a

from fastapi_icontract import ensure

@app.get("/books_in_category", response_model=List[Book])
@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."""
    ...

The following snippet is a rather sophisticated one that involves both the post-condition and a snapshot (see the full example):

import asynstdlib as a
from fastapi_icontract import snapshot, ensure

@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:
    ...