Skip to main content

An ASGI middleware to populate OpenAPI Specification examples from pytest functions

Project description

PyTest-API: Populate OpenAPI Examples from Python Tests

purpose PyPI

PyTest-API is an ASGI middleware that populates OpenAPI-Specification examples from pytest functions.

Installation

poetry add --dev pytest-api

How to use it:

Starting with test_main.py file:

from .main import spec


@spec.describe(route="/behavior-example/")
def test_example_body(client):
    """
    GIVEN behavior in body
    WHEN example behavior endpoint is called with POST method
    THEN response with status 200 and body OK is returned
    """
    assert client.post(
        "/behavior-example/", json={"name": "behavior"},
        headers={"spec-example": test_example_body.id}
    ).json() == {"message": "OK"}

Impliment solution in /main.py file:

from fastapi import FastAPI
from pydantic import BaseModel

from pytest_api import ASGIMiddleware

app = FastAPI()
spec = ASGIMiddleware

app.add_middleware(spec)

app.openapi = spec.openapi_behaviors(app)


class Behavior(BaseModel):
    name: str


@app.post("/behavior-example/")
async def example_body(behavior: Behavior):
    return {"message": "OK"}

Run FastAPI app:

poetry run uvicorn test_app.main:app --reload

Open your browser to http://localhost:8000/docs#/ too find the doc string is populated into the description.

Your doc string will now be populated into the description.

Implimentation Details

Under the hood the ASGIMiddleware uses the describe decorator to store the pytest function by its id:

def wrap_behavior(*args, **kwargs):
                try:
                    BEHAVIORS[route]
                except KeyError as e:
                    if route in e.args:
                        BEHAVIORS[route] = {str(id(func)): func}
                BEHAVIORS[route][str(id(func))] = func

When pytest calls your API the SpecificationResponder is looking for the coresponding id in the headers of the request:

    def handle_spec(self, headers):
        behaviors = BEHAVIORS[self.path]
        self.should_update_example = headers.get("spec-example", "") in behaviors
        self.should_update_description = (
            headers.get("spec-description", "") in behaviors
        )

        if self.should_update_example:
            self.func = behaviors[headers.get("spec-example")]
        elif self.should_update_description:
            self.func = behaviors[headers.get("spec-description")]

This is possible thanks to python's first-class functions i.e. Closure_(computer_programming).

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

pytest_api-0.1.4.tar.gz (5.9 kB view hashes)

Uploaded Source

Built Distribution

pytest_api-0.1.4-py3-none-any.whl (6.4 kB view hashes)

Uploaded Python 3

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