Pre-release
This release is a pre-release and may not be stable for production use.
jj
Installation
pip3 install jj==2.0.0-dev.5
Usage
import jj
@jj.match("*")
async def handler(request: jj.Request) -> jj.Response:
return jj.Response(body="200 OK")
jj.serve()
Documentation
Matchers
Method
match_method(method)
from jj.http.methods import ANY, GET, POST
@jj.match_method(GET)
async def handler(request):
return jj.Response(body="Method: " + request.method)
Path
match_path(path)
@jj.match_path("/users")
async def handler(request):
return jj.Response(body="Path: " + request.path)
Segments
@jj.match_path("/users/{users_id}")
async def handler(request):
return jj.Response(body=f"Segments: {request.segments}")
More information available here https://docs.aiohttp.org/en/stable/web_quickstart.html#variable-resources
Params
match_param(name, val)
@jj.match_param("locale", "en_US")
async def handler(request):
locales = request.params.getall('locale')
return jj.Response(body="Locales: " + ",".join(locales))
match_params(params)
@jj.match_params({"locale": "en_US", "timezone": "UTC"})
async def handler(request):
# Literal String Interpolation (PEP 498)
return jj.Response(body=f"Params: {request.params}")
Headers
match_header(name, val)
@jj.match_header("X-Forwarded-Proto", "https")
async def handler(request):
proto = request.headers.getone("X-Forwarded-Proto")
return jj.Response(body="Proto: " + proto)
match_headers(headers)
@jj.match_headers({
"x-user-id": "1432",
"x-client-id": "iphone",
})
async def handler(request):
return jj.Response(body=f"Headers: {request.headers}")
Combining Matchers
match_any(matchers)
from jj.http import PATCH, PUT
@jj.match_any([
jj.match_method(PUT),
jj.match_method(PATCH),
])
async def handler(request):
return jj.Response(body="200 OK")
match_all(matchers)
@jj.match_all([
jj.match_method("*"),
jj.match_path("/"),
jj.match_params({"locale": "en_US"}),
jj.match_headers({"x-request-id": "0fefbf48"}),
])
async def handler(request):
return jj.Response(body="200 OK")
match(method, path, params, headers)
@jj.match("*", "/", {"locale": "en_US"}, {"x-request-id": "0fefbf48"})
async def handler(request):
return jj.Response(body="200 OK")
Responses
Response
JSON Response
@jj.match("*")
async def handler(request):
return jj.Response(json={"message": "200 OK"})
HTML Response
@jj.match("*")
async def handler(request):
return jj.Response(body="<p>text<p>", headers={"Content-Type": "text/html"})
Binary Response
@jj.match("*")
async def handler(request):
return jj.Response(body=b"<binary>")
Not Found Response
@jj.match("*")
async def handler(request):
return jj.Response(status=404, reason="Not Found")
Predefined Body
from jj.http import GET
@jj.match(GET, "/users")
async def handler(request):
return jj.Response(body=open("responses/users.json", "rb"))
from jj.http import POST, CREATED
@jj.match(POST, "/users")
async def handler(request):
return jj.Response(body=open("responses/created.json", "rb"), status=CREATED)
StaticResponse
Inline Content
from jj.http import GET
@jj.match(GET, "/image")
async def handler(request):
return jj.StaticResponse("public/image.jpg")
Downloadable File
from jj.http import GET
@jj.match(GET, "/report")
async def handler(request):
return jj.StaticResponse("public/report.csv", attachment=True)
from jj.http import GET
@jj.match(GET, "/")
async def handler(request):
return jj.StaticResponse("public/report.csv", attachment="report.csv")
For more information visit https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition
RelayResponse β
@jj.match("*")
async def handler(request):
return jj.RelayResponse(target="https://httpbin.org/")
Apps
Single App
import jj
from jj.http.methods import GET, ANY
from jj.http.codes import OK, NOT_FOUND
class App(jj.App):
@jj.match(GET, "/")
async def root_handler(self, request: jj.Request) -> jj.Response:
return jj.Response(status=OK, json={"message": "200 OK"})
@jj.match(ANY)
async def default_handler(self, request: jj.Request) -> jj.Response:
return jj.Response(status=NOT_FOUND, json={"message": "Not Found"})
jj.serve(App(), port=5000)
Multiple Apps
import jj
class App(jj.App):
@jj.match("*")
async def handler(self, request: jj.Request) -> jj.Response:
return jj.Response(body="App")
class AnotherApp(jj.App):
@jj.match("*")
async def handler(self, request: jj.Request) -> jj.Response:
return jj.Response(body="AnotherApp")
jj.start(App(), port=5001)
jj.start(AnotherApp(), port=5002)
jj.wait_for([KeyboardInterrupt])
App Inheritance
import jj
class UsersApp(jj.App):
@jj.match("*", path="/users")
async def handler(self, request: jj.Request) -> jj.Response:
return jj.Response(body="Users")
class GroupsApp(jj.App):
@jj.match("*", path="/groups")
async def handler(self, request: jj.Request) -> jj.Response:
return jj.Response(body="Groups")
class App(UsersApp, GroupsApp):
pass
jj.serve(App())
Middlewares
Handler Middleware
import jj
from jj.http.codes import OK, FORBIDDEN
class Middleware(jj.Middleware):
async def do(self, request, handler, app):
if request.headers.get("x-secret-key") != "<SECRET_KEY>":
return jj.Response(status=FORBIDDEN, body="Forbidden")
return await handler(request)
class App(jj.App):
@Middleware()
@jj.match("*")
async def handler(self, request: jj.Request) -> jj.Response:
return jj.Response(status=OK, body="Ok")
jj.serve(App())
App Middleware
import jj
from jj.http.codes import OK, FORBIDDEN
class ReusableMiddleware(jj.Middleware):
def __init__(self, secret_key):
super().__init__()
self._secret_key = secret_key
async def do(self, request, handler, app):
if request.headers.get("x-secret-key") != self._secret_key:
return jj.Response(status=FORBIDDEN, body="Forbidden")
return await handler(request)
private = ReusableMiddleware("<SECRET_KEY>")
@private
class App(jj.App):
@jj.match("*")
async def handler(self, request: jj.Request) -> jj.Response:
return jj.Response(status=OK, body="Ok")
jj.serve(App())
Metadata
Release files for jj 2.0.0.dev5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| jj-2.0.0.dev5.tar.gz | 44.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| jj-2.0.0.dev5-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 133.1 kB
Release files / jj-2.0.0.dev5.tar.gz
| Download URL | jj-2.0.0.dev5.tar.gz |
|---|---|
| Size | 44.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d71e16ab5c70df1dae4e6ec60ee3f7c834e177709fb9b6e2fdb412eee497eb56
|
|
BLAKE2b-256 checksum How to use checksums |
9188cde07b969adfe8c12b7bb0d02cda5705104efc723180fae46d7362bcc5d1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/50.3.0 requests-toolbelt/0.9.1 tqdm/4.48.2 CPython/3.8.5
|
Release files / jj-2.0.0.dev5-py3-none-any.whl
| Download URL | jj-2.0.0.dev5-py3-none-any.whl |
|---|---|
| Size | 88.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0148a5ce3f9845665cbde83e31fda1fbcb6a88fb8dc356cf9cf64a54b9096b5f
|
|
BLAKE2b-256 checksum How to use checksums |
f2b08addbc08229bc95ecefa49d6965ced44320f5d3f86fae83c08f9ea5f8fb3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/3.2.0 pkginfo/1.5.0.1 requests/2.24.0 setuptools/50.3.0 requests-toolbelt/0.9.1 tqdm/4.48.2 CPython/3.8.5
|