Middletools
This is a python library that allows you to integrate middlewares-based system to your project. It contains base tools for creating and running middlewares with async-await style
Installation
PyPI
python -m pip install middletools
GitHub
python -m pip install https://github.com/deknowny/middlewares/archive/main.zip
Usage
The main idea is give an ability just passing the middlewares and inbox/outbox payload values in a few methods instead of running and saving middlewares state by hand
Standard case: a function runs RESTful API routers and requires a middleware that checks a header in client's request
There are 2 endpoints for an abstract GET and POST methods
# Some abstract router
@router.get("/")
async def route_get(request):
return 200, {"response": "some content"}
@router.post("/")
async def route_post(request):
return 201, {"response": "ok"}
In the core of web framework you used a function like this that just call all routers
class Router:
...
...
async def call_routers(self, request):
for router in self.routers:
... # Pass request to routers and check it matched
middlewares library allows you easy integrate middleware system to your call_routers
Create middleware function
import middletools
...
...
# Adding a middleware handler to an abstract
@router.add_middleware
async def my_middleware(
request: SomeRequest, call_next: middletools.types.CallNext
) -> SomeResponse:
# Just check if header exists, id not set the default value
if "X-Required-Header" not in request.headers:
request.header["X-Required-Header"] = "default"
response = await call_next()
return response
Here we add a header to client request if clint didn't do it. Then await call_next() give control to other middlewares or to our call_routers handler and response from this is the value call_next() returns
call_routers should looks like this
import typing
import middletools
class Router:
# You can use generics to describe middleware hand;er
middlewares: typing.List[
middletools.types.MiddlewareHandler[
SomeRequest, SomeResponse
]
]
...
...
async def call_routers(self, request):
read_afterwords = await middletools.read_forewords(
*self.middlewares, inbox_value=request
)
for router in self.routers:
... # Pass request to routers and check it matched
response = ...
await read_afterwords(response)
break
middlewares.read_forewords run middlewares until every one of them give control with await call_next().
When we do all our stuff and get the router response we can call await read_afterwords(response) and run all middlewares completely.
Notes
If a middleware doesn't call call_next() it raises middlewares.CallNextNotUsedError. It means that the middleware forcibly decline middlewares handlers and response should be sent immediately without routers running. call_routers should looks like this:
import middletools
async def call_routers(self, request):
try:
read_afterwords = await middletools.read_forewords(
*self.middlewares, inbox_value=request
)
for router in self.routers:
... # Pass request to routers and check it matched
response = ...
await read_afterwords(response)
return response
except middletools.CallNextNotUsedError:
return SomeBadResponseBecauseNotRouted(400, "Require a header!")
If a middleware doesn't return anything, middlewares dispatching declined forcibly too but after routers handled. (Return nothing means there isn't any return or return None used). It raises middlewares.NothingReturnedError
import middletools
async def call_routers(self, request):
try:
read_afterwords = await middletools.read_forewords(
*self.middlewares, inbox_value=request
)
for router in self.routers:
... # Pass request to routers and check it matched
response = ...
await read_afterwords(response)
return response
except middletools.CallNextNotUsedError:
return SomeBadResponseBecauseNotRouted(400, "Require a header!")
except middletools.NothingReturnedError:
return SomeBadResponseBecauseMiddlewareDntReturnResponse(
500, "Oops, internal server error"
)
Metadata
Release files for middletools 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| middletools-0.1.2.tar.gz | 5.5 kB | Without provenance | Details for middletools-0.1.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| middletools-0.1.2-py3-none-any.whl | Python 3 | none | any | Details for middletools-0.1.2-py3-none-any.whl |
Total release size: 11.3 kB
Release files / middletools-0.1.2.tar.gz
| Download URL | middletools-0.1.2.tar.gz |
|---|---|
| Size | 5.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
12d58c44258126dfac4f91d265aee9f42751745d1d9738d07cfdd9f0de14b77b
|
|
BLAKE2b-256 checksum How to use checksums |
67503acc5c10ce5772d4fc7fe62109da6d78d237e2ff1d833420195cba7d9fc3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.1.4 CPython/3.9.1 Darwin/19.3.0
|
Release files / middletools-0.1.2-py3-none-any.whl
| Download URL | middletools-0.1.2-py3-none-any.whl |
|---|---|
| Size | 5.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6a2cef863244be65df4125e623d6b21056d351507b4faa917d25049673d8ad1d
|
|
BLAKE2b-256 checksum How to use checksums |
47fbde15c09ec7a31cd270bffaec3b4dbb15840f8964e9371c24a2478b263118
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.1.4 CPython/3.9.1 Darwin/19.3.0
|
Security for middletools 0.1.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.