# drakaina
![Drakaina](content/drakaina.png "Drakaina"){width=200px height=205px}
[![image](https://img.shields.io/pypi/v/drakaina.svg)](https://pypi.python.org/pypi/drakaina)
[![image](https://img.shields.io/pypi/l/drakaina.svg)](https://pypi.python.org/pypi/drakaina)
[![image](https://img.shields.io/pypi/pyversions/drakaina.svg)](https://pypi.python.org/pypi/drakaina)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v1.json)](https://github.com/charliermarsh/ruff)
[![Code style: black](https://img.shields.io/badge/code%20style-black-black.svg)](https://github.com/psf/black)
[![libera manifesto](https://img.shields.io/badge/libera-manifesto-lightgrey.svg)](https://liberamanifesto.com)
❗ WIP
Module for simple RPC service implementation
## Quickstart
Drakaina may be installed via `pip` and requires Python 3.7 or higher :
```shell
pip install drakaina
```
A minimal Drakaina example is:
```python
from drakaina import remote_procedure
from drakaina.wsgi import WSGIHandler
@remote_procedure
def my_method():
return "Hello Bro! ✋️"
@remote_procedure(name="something.get")
def get_some_string():
return "You called `something.get`."
@remote_procedure(provide_request=True)
def do_something_with_environ(request):
return f"You called `do_something_with_environ`. Request: {request}."
@remote_procedure()
def tell_the_middleware_something():
return "You called `tell_the_middleware_something`. It has a some extra conditions."
async def asynchronous_procedure():
await asyncio.sleep(5)
return "Ding-Dong 🔔!"
"""
>>> JsonRPCv2().handle({"jsonrpc": "2.0", "method": "my_method", "id": 1})
or define WSGI application
"""
app = WSGIHandler(route="/jrpc")
```
Drakaina may be ran with any WSGI-compliant server,
such as [Gunicorn](http://gunicorn.org).
```shell
gunicorn main:app
```
## Features
- Serializers layer.
- `json`, `orjson`, `ujson` and `msgpack` serializers.
- `login_required` and `check_permissions` decorators.
- WSGI protocol implementation
- CORS middleware
- JWT Authorization middleware.
- Compatible with simple middlewares for others wsgi-frameworks,
like as [Werkzeug](https://palletsprojects.com/p/werkzeug/),
[Flask](https://palletsprojects.com/p/flask/)
# Documentation
## Installation
```shell
pip install drakaina
```
## Middlewares
### CORS
### JWT
Drakaina may be installed via `pip` and requires Python 3.7 or higher :
```shell
pip install drakaina[jwt]
```
A minimal Drakaina example is:
```python
from functools import partial
from drakaina import ENV_IS_AUTHENTICATED
from drakaina import ENV_USER_ID
from drakaina import remote_procedure
from drakaina import check_permissions
from drakaina import login_required
from drakaina import match_any
from drakaina.contrib.jwt.middleware import JWTAuthenticationMiddleware
from drakaina.wsgi import WSGIHandler
import user_store
@login_required
@remote_procedure(provide_request=True)
def my_method(request):
assert request[ENV_IS_AUTHENTICATED]
return f"Hello Bro ✋! Your ID={request[ENV_USER_ID]}"
@check_permissions(["user_read", "user:admin", "username:johndoe"], match_any)
@remote_procedure
def my_method():
return "Hello Bro! ✋️"
def get_user(request, payload):
user_id = request[ENV_USER_ID] or payload["user_id"]
return user_store.get(id=user_id)
def get_jwt_scopes(request, payload):
# here `scp` is the key for the scopes value in the token payload
return payload.get("scp")
app = WSGIHandler(
middlewares=[
partial(
JWTAuthenticationMiddleware,
secret_phrase="_secret_",
credentials_required=True,
auth_scheme="Bearer",
# token_getter=custom_implementation_get_token,
user_getter=get_user,
scopes_getter=get_jwt_scopes,
# revoke_checker=is_revoked,
)
]
)
```
### Using with Django
Create file `rpc_views.py` in your django application.
Define function and wrap it `remote_procedure` decorator:
```python
from drakaina import remote_procedure
@remote_procedure
def my_method():
return "Hello, Django Bro! ✋"
```
Add `RPCView` class to urlpatterns. The `as_view` method
must accept the `autodiscover` argument as the name of
the remote procedure files.
```python
from django.urls import path
from drakaina.contrib.django.views import RPCView
urlpatterns = [
...,
path("api/", RPCView.as_view(autodiscover="rpc_views")),
]
```
### JWT Authentication in your Django project
Wrap an instance of `RPCView` with the `JWTAuthenticationMiddleware`.
```python
from django.urls import path
from drakaina.contrib.django import RPCView, JWTAuthenticationMiddleware
urlpatterns = [
...,
path("api/", JWTAuthenticationMiddleware(
RPCView.as_view(autodiscover="rpc_views")
)),
]
```
Define the parameters in the `settings.py` file.
```python
...
DRAKAINA_JWT_SECRET_KEY = "__SECRET_KEY__"
...
```
## License
Apache License 2.0
## Artwork
"[drakaina.png](content/drakaina.png)" by Korolko Anastasia is licensed under
<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"><img alt="License Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-sa/4.0/80x15.png" /></a> ([CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)).
Raw data
{
"_id": null,
"home_page": "https://gitlab.com/tau_lex/drakaina",
"name": "drakaina",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.7,<4.0",
"maintainer_email": "",
"keywords": "rpc,jsonrpc",
"author": "Aleksey Terentyev",
"author_email": "terentyev.a@pm.me",
"download_url": "https://files.pythonhosted.org/packages/9e/ed/e744c138355776b26655d7b2819b20a5a1ee943679a2e9dcb576d4b3ea39/drakaina-0.6.19.tar.gz",
"platform": null,
"description": "# drakaina\n\n![Drakaina](content/drakaina.png \"Drakaina\"){width=200px height=205px}\n\n[![image](https://img.shields.io/pypi/v/drakaina.svg)](https://pypi.python.org/pypi/drakaina)\n[![image](https://img.shields.io/pypi/l/drakaina.svg)](https://pypi.python.org/pypi/drakaina)\n[![image](https://img.shields.io/pypi/pyversions/drakaina.svg)](https://pypi.python.org/pypi/drakaina)\n[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v1.json)](https://github.com/charliermarsh/ruff)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-black.svg)](https://github.com/psf/black)\n[![libera manifesto](https://img.shields.io/badge/libera-manifesto-lightgrey.svg)](https://liberamanifesto.com)\n\n\u2757 WIP\n\nModule for simple RPC service implementation\n\n\n## Quickstart\n\nDrakaina may be installed via `pip` and requires Python 3.7 or higher :\n\n```shell\npip install drakaina\n```\n\nA minimal Drakaina example is:\n\n```python\nfrom drakaina import remote_procedure\nfrom drakaina.wsgi import WSGIHandler\n\n\n@remote_procedure\ndef my_method():\n return \"Hello Bro! \u270b\ufe0f\"\n\n\n@remote_procedure(name=\"something.get\")\ndef get_some_string():\n return \"You called `something.get`.\"\n\n\n@remote_procedure(provide_request=True)\ndef do_something_with_environ(request):\n return f\"You called `do_something_with_environ`. Request: {request}.\"\n\n\n@remote_procedure()\ndef tell_the_middleware_something():\n return \"You called `tell_the_middleware_something`. It has a some extra conditions.\"\n\n\nasync def asynchronous_procedure():\n await asyncio.sleep(5)\n return \"Ding-Dong \ud83d\udd14!\"\n\n\n\"\"\"\n>>> JsonRPCv2().handle({\"jsonrpc\": \"2.0\", \"method\": \"my_method\", \"id\": 1})\nor define WSGI application\n\"\"\"\napp = WSGIHandler(route=\"/jrpc\")\n```\n\nDrakaina may be ran with any WSGI-compliant server,\nsuch as [Gunicorn](http://gunicorn.org).\n\n```shell\ngunicorn main:app\n```\n\n\n## Features\n\n- Serializers layer.\n - `json`, `orjson`, `ujson` and `msgpack` serializers.\n- `login_required` and `check_permissions` decorators.\n- WSGI protocol implementation\n - CORS middleware\n - JWT Authorization middleware.\n - Compatible with simple middlewares for others wsgi-frameworks,\n like as [Werkzeug](https://palletsprojects.com/p/werkzeug/),\n [Flask](https://palletsprojects.com/p/flask/)\n\n\n# Documentation\n\n\n## Installation\n\n```shell\npip install drakaina\n```\n\n\n## Middlewares\n\n\n### CORS\n\n\n### JWT\n\nDrakaina may be installed via `pip` and requires Python 3.7 or higher :\n\n```shell\npip install drakaina[jwt]\n```\n\nA minimal Drakaina example is:\n\n```python\nfrom functools import partial\nfrom drakaina import ENV_IS_AUTHENTICATED\nfrom drakaina import ENV_USER_ID\nfrom drakaina import remote_procedure\nfrom drakaina import check_permissions\nfrom drakaina import login_required\nfrom drakaina import match_any\nfrom drakaina.contrib.jwt.middleware import JWTAuthenticationMiddleware\nfrom drakaina.wsgi import WSGIHandler\n\nimport user_store\n\n\n@login_required\n@remote_procedure(provide_request=True)\ndef my_method(request):\n assert request[ENV_IS_AUTHENTICATED]\n return f\"Hello Bro \u270b! Your ID={request[ENV_USER_ID]}\"\n\n\n@check_permissions([\"user_read\", \"user:admin\", \"username:johndoe\"], match_any)\n@remote_procedure\ndef my_method():\n return \"Hello Bro! \u270b\ufe0f\"\n\n\ndef get_user(request, payload):\n user_id = request[ENV_USER_ID] or payload[\"user_id\"]\n return user_store.get(id=user_id)\n\n\ndef get_jwt_scopes(request, payload):\n # here `scp` is the key for the scopes value in the token payload\n return payload.get(\"scp\")\n\n\napp = WSGIHandler(\n middlewares=[\n partial(\n JWTAuthenticationMiddleware,\n secret_phrase=\"_secret_\",\n credentials_required=True,\n auth_scheme=\"Bearer\",\n # token_getter=custom_implementation_get_token,\n user_getter=get_user,\n scopes_getter=get_jwt_scopes,\n # revoke_checker=is_revoked,\n )\n ]\n)\n```\n\n\n### Using with Django\n\nCreate file `rpc_views.py` in your django application.\nDefine function and wrap it `remote_procedure` decorator:\n\n```python\nfrom drakaina import remote_procedure\n\n@remote_procedure\ndef my_method():\n return \"Hello, Django Bro! \u270b\"\n```\n\nAdd `RPCView` class to urlpatterns. The `as_view` method\nmust accept the `autodiscover` argument as the name of\nthe remote procedure files.\n\n```python\nfrom django.urls import path\nfrom drakaina.contrib.django.views import RPCView\n\nurlpatterns = [\n ...,\n path(\"api/\", RPCView.as_view(autodiscover=\"rpc_views\")),\n]\n```\n\n\n### JWT Authentication in your Django project\n\nWrap an instance of `RPCView` with the `JWTAuthenticationMiddleware`.\n\n```python\nfrom django.urls import path\nfrom drakaina.contrib.django import RPCView, JWTAuthenticationMiddleware\n\nurlpatterns = [\n ...,\n path(\"api/\", JWTAuthenticationMiddleware(\n RPCView.as_view(autodiscover=\"rpc_views\")\n )),\n]\n```\n\nDefine the parameters in the `settings.py` file.\n\n```python\n...\n\nDRAKAINA_JWT_SECRET_KEY = \"__SECRET_KEY__\"\n\n...\n```\n\n\n## License\n\nApache License 2.0\n\n## Artwork\n\n\"[drakaina.png](content/drakaina.png)\" by Korolko Anastasia is licensed under\n<a rel=\"license\" href=\"http://creativecommons.org/licenses/by-sa/4.0/\"><img alt=\"License Creative Commons\" style=\"border-width:0\" src=\"https://i.creativecommons.org/l/by-sa/4.0/80x15.png\" /></a> ([CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)).\n",
"bugtrack_url": null,
"license": "Apache-2.0",
"summary": "Module for simple RPC service implementation",
"version": "0.6.19",
"project_urls": {
"Homepage": "https://gitlab.com/tau_lex/drakaina",
"Repository": "https://gitlab.com/tau_lex/drakaina"
},
"split_keywords": [
"rpc",
"jsonrpc"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "f559328014f0962d8bee1abde2d44d540e4b6876979f43d0812f99726f68359b",
"md5": "105836d3fd3d03296aebf5775223d134",
"sha256": "eae989df9fba8ec9b8d7b009d0fe7a780fa809e7a5b86411b1698e59def61e7d"
},
"downloads": -1,
"filename": "drakaina-0.6.19-py3-none-any.whl",
"has_sig": false,
"md5_digest": "105836d3fd3d03296aebf5775223d134",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7,<4.0",
"size": 54543,
"upload_time": "2023-04-28T17:23:53",
"upload_time_iso_8601": "2023-04-28T17:23:53.982688Z",
"url": "https://files.pythonhosted.org/packages/f5/59/328014f0962d8bee1abde2d44d540e4b6876979f43d0812f99726f68359b/drakaina-0.6.19-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "9eede744c138355776b26655d7b2819b20a5a1ee943679a2e9dcb576d4b3ea39",
"md5": "a2609864a8f0df65671bc9800bd1d038",
"sha256": "fe01cf5c24a2f711d0e7dbd1759506110272d37e5d36ea99af3c7a9b34cd3b24"
},
"downloads": -1,
"filename": "drakaina-0.6.19.tar.gz",
"has_sig": false,
"md5_digest": "a2609864a8f0df65671bc9800bd1d038",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7,<4.0",
"size": 45083,
"upload_time": "2023-04-28T17:23:56",
"upload_time_iso_8601": "2023-04-28T17:23:56.789714Z",
"url": "https://files.pythonhosted.org/packages/9e/ed/e744c138355776b26655d7b2819b20a5a1ee943679a2e9dcb576d4b3ea39/drakaina-0.6.19.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-04-28 17:23:56",
"github": false,
"gitlab": true,
"bitbucket": false,
"codeberg": false,
"gitlab_user": "tau_lex",
"gitlab_project": "drakaina",
"lcname": "drakaina"
}