tombulled / mediate

Middleware for every occasion
https://pypi.org/project/mediate/
MIT License
0 stars 0 forks source link

Improve Type Annotations #5

Closed tombulled closed 1 year ago

tombulled commented 2 years ago

E.g. make Middleware generic (Middleware[In, Out])

Each middleware function should have a type like this:

MiddlewareFunc = Callable[[MiddlewareFunc, T], T]

An entrypoint should look like this:

MiddlewareEntrypoint = Callable[..., T]
tombulled commented 1 year ago

Conceptually, every piece of middleware can take in one thing, and return one thing, aka Callable[[In], Out]. However, the user may want to provide a "funnel" to produce In. Here's an example "funnel":

def build_request(method: str, path: str) -> Request:
    return Request(method=method, path=path)

In the above example, build_request would sit at the front of all of the middleware (and In would become bound to Request). A funnel is entirely optional, as the user might rock up with a Request to begin with (in this case an identity function could represent the funnel). Then, each middleware callable could look like this:

class RequestMiddleware(Protocol):
    def __call__(self, request: Request, /) -> Response:
        ...

def do_something(call_next: RequestMiddleware, request: Request, /) -> Response:
    request.headers["message"] = "Hello, World!"

    return call_next(request)

However, none of the middleware should be responsible for converting a Request into a Response, instead a user-provided "sinc" should do this:

def send_request(request: Request, /) -> Response:
    return httpx.request(request)