Skip to content

Flask

Flask provider example.

This modules defines a simple provider which will be tested with Pact in the provider test. As Pact is a consumer-driven framework, the consumer defines the contract which the provider must then satisfy.

The provider is the application which receives requests from another service (the consumer) and returns a response. In this example, we have a simple endpoint which returns a user's information from a (fake) database.

This also showcases how Pact tests differ from merely testing adherence to an OpenAPI specification. The Pact tests are more concerned with the practical use of the API, rather than the formally defined specification. The User class defined here has additional fields which are not used by the consumer. Should the provider later decide to add or remove fields, Pact's consumer-driven testing will provide feedback on whether the consumer is compatible with the provider's changes.

Note that the code in this module is agnostic of Pact (i.e., this would be your production code). The pact-python dependency only appears in the tests. This is because the consumer is not concerned with Pact, only the tests are.

Attributes

FAKE_DB: dict[int, User] = {} module-attribute

app = Flask(__name__) module-attribute

logger = logging.getLogger(__name__) module-attribute

Classes

User(id: int, name: str, created_on: datetime, email: str | None, ip_address: str | None, hobbies: list[str], admin: bool) dataclass

User data class.

Attributes

admin: bool instance-attribute
created_on: datetime instance-attribute
email: str | None instance-attribute
hobbies: list[str] instance-attribute
id: int instance-attribute
ip_address: str | None instance-attribute
name: str instance-attribute

Functions

dict() -> dict[str, Any]

Return the user's data as a dict.

Source code in examples/src/flask.py
def dict(self) -> dict[str, Any]:
    """
    Return the user's data as a dict.
    """
    return {
        "id": self.id,
        "name": self.name,
        "created_on": self.created_on.strftime("%Y-%m-%dT%H:%M:%S%z"),
        "email": self.email,
        "ip_address": self.ip_address,
        "hobbies": self.hobbies,
        "admin": self.admin,
    }

Functions

create_user() -> Response

Source code in examples/src/flask.py
@app.route("/users/", methods=["POST"])
def create_user() -> Response:
    if request.json is None:
        abort(400, description="Invalid JSON data")

    user: dict[str, Any] = request.json
    uid = len(FAKE_DB)
    FAKE_DB[uid] = User(
        id=uid,
        name=user["name"],
        created_on=datetime.now(tz=timezone.utc),
        email=user.get("email"),
        ip_address=user.get("ip_address"),
        hobbies=user.get("hobbies", []),
        admin=user.get("admin", False),
    )
    return jsonify(FAKE_DB[uid].dict())

delete_user(uid: int) -> tuple[str | Response, int]

Source code in examples/src/flask.py
@app.route("/users/<int:uid>", methods=["DELETE"])
def delete_user(uid: int) -> tuple[str | Response, int]:
    if uid not in FAKE_DB:
        return jsonify({"detail": "User not found"}), 404
    del FAKE_DB[uid]
    return "", 204

get_user_by_id(uid: int) -> Response | tuple[Response, int]

Fetch a user by their ID.

PARAMETER DESCRIPTION
uid

The ID of the user to fetch

TYPE: int

RETURNS DESCRIPTION
Response | tuple[Response, int]

The user data if found, HTTP 404 if not

Source code in examples/src/flask.py
@app.route("/users/<int:uid>")
def get_user_by_id(uid: int) -> Response | tuple[Response, int]:
    """
    Fetch a user by their ID.

    Args:
        uid: The ID of the user to fetch

    Returns:
        The user data if found, HTTP 404 if not
    """
    user = FAKE_DB.get(uid)
    if not user:
        return jsonify({"detail": "User not found"}), 404
    return jsonify(user.dict())