rAPIdy


NamerAPIdy JSON
Version 0.1.1 PyPI version JSON
download
home_page
SummaryrAPIdy - write quickly - write beautifully
upload_time2024-02-29 16:46:33
maintainer
docs_urlNone
authorDaniil Grois
requires_python>=3.8,<4.0
licenseMIT
keywords rapidy aiohttp pydantic api fast http server daniil grois
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            
# rAPIdy 💮
**write quickly** 🚀 **write beautifully** 🌸

<a href="https://github.com/daniil-grois/rAPIdy">rAPIdy<a/> is a minimalistic, asynchronous, fast web framework based in aiohttp and pydantic.

```
pip install rapidy
```

Key Features:
* ✏️ easy to write and read code
* 📔 <a href="https://github.com/pydantic/pydantic">pydantic<a/> native support -> **yes** we support **V**1️⃣ and **V**2️⃣❗
* 🚀 <a href="https://github.com/aio-libs/aiohttp">aiohttp<a/> based and native features support - aiohttp one of the fastest and most productive HTTP servers
* 📤 convenient support for basic types of incoming data extraction

## Quickstart

### Create endpoint using RouteTableDef

rAPIdy inherits the basic functionality of aiohttp <a href="https://docs.aiohttp.org/en/stable/web_quickstart.html">quickstart</a>

```python
from rapidy import web
from typing_extensions import Annotated

routes = web.RouteTableDef()


@routes.get('/hello')
async def hello(
        request: web.Request,
        username: Annotated[str, web.JsonBody(min_length=3, max_length=20)],
        password: Annotated[str, web.JsonBody(min_length=8, max_length=40)],
) -> web.Response:
  # write you business code here
  return web.json_response({'username': username, 'password': password})


app = web.Application()
app.add_routes(routes)

if __name__ == '__main__':
  web.run_app(app, port=8000)
```

### Create endpoint using web.<method_name>

```python
from rapidy import web
from typing_extensions import Annotated


async def hello(
        request: web.Request,
        username: Annotated[str, web.JsonBody(min_length=3, max_length=20)],
        password: Annotated[str, web.JsonBody(min_length=8, max_length=40)],
) -> web.Response:
  # write you business code here
  return web.json_response({'username': username, 'password': password})


app = web.Application()
app.add_routes([web.post('/hello', hello)])

if __name__ == '__main__':
  web.run_app(app, port=8000)
```

### Create endpoint using web.view

```python
from rapidy import web
from typing_extensions import Annotated


class Handler(web.View):
  async def post(
          self,
          username: Annotated[str, web.JsonBody(min_length=3, max_length=20)],
          password: Annotated[str, web.JsonBody(min_length=8, max_length=40)],
  ) -> web.Response:
    # write you business code here
    return web.json_response({'username': username, 'password': password})


app = web.Application()
app.add_routes([web.view('/hello', Handler)])

if __name__ == '__main__':
  web.run_app(app, port=8000)
```

## Pydantic native support

```python
from rapidy import web
from typing_extensions import Annotated


async def hello_handler(
        request: web.Request,
        username: Annotated[str, web.JsonBody(min_length=3, max_length=20)],
        password: Annotated[str, web.JsonBody(min_length=8, max_length=40)],
) -> web.Response:
  # write you business code here
  return web.json_response({'username': username, 'password': password})


app = web.Application()
app.add_routes([web.post('/hello', hello_handler)])
web.run_app(app, port=8000)
```
✅✅✅ Success request validation ✅✅✅
```
curl -X POST \
-H "Content-Type: application/json" -d '{"username": "Max", "password": "myAwesomePass"}' -v \
http://127.0.0.1:8000/hello

< HTTP/1.1 200 OK ... {"username": "Max", "password": "myAwesomePass"}
```

❌❌❌ Request validation failure ❌❌❌

```
curl -X POST \
-H "Content-Type: application/json" -d '{"username": "M", "password": "m"}' -v \
http://127.0.0.1:8000/hello

< HTTP/1.1 422 Unprocessable Entity ...
{
    "errors": [
        {
            "loc": ["body", "username"],
            "type": "string_too_short",
            "msg": "String should have at least 3 characters",
            "ctx": {"min_length": 3}
        },
        {
            "type": "string_too_short",
            "loc": ["body", "password"],
            "msg": "String should have at least 8 characters",
            "ctx": {"min_length": 8}
        }
    ]
}

```

## Choose your path

* You can create APIs the way you want.
* **rAPIdy** supports 3 basic types for defining incoming parameters
  * 🌒 param
    * Path
    * Header
    * Cookie
    * Query
    * BodyJson
    * FormDataBody
    * MultipartBody
  * 🌕 schema
    * PathSchema
    * HeaderSchema
    * CookieSchema
    * QuerySchema
    * BodyJsonSchema
    * FormDataBodySchema
    * MultipartBodySchema
  * 🌑 raw data (no validate with pydantic)
    * PathRaw - **Dict[str, str]**
    * HeaderRaw - **Dict[str, str]**
    * CookieRaw - **Dict[str, str]**
    * QueryRaw - **Dict[str, str]**
    * BodyJsonRaw - **Dict[str, Any]**
    * FormDataBodyRaw - **Dict[str, Any]**
    * MultipartBodyRaw - **Dict[str, Any]**
    * TextBody - **str**
    * BytesBody - **bytes**
    * StreamBody - **aiohttp.streams.StreamReader**

```python
# defining request attributes as param 🌒
from rapidy import web
from typing_extensions import Annotated


async def hello_handler(
        request: web.Request,
        # path params
        path_param: Annotated[str, web.Path],
        # headers
        host: Annotated[str, web.Header(alias='Host')],
        user_agent: Annotated[str, web.Header(alias='User-Agent')],
        # cookie
        user_cookie1: Annotated[str, web.Cookie(alias='UserCookie1')],
        user_cookie2: Annotated[str, web.Cookie(alias='UserCookie2')],
        # query params
        user_param1: Annotated[str, web.Query(alias='UserQueryParam1')],
        user_param2: Annotated[str, web.Cookie(alias='UserQueryParam2')],
        # body
        username: Annotated[str, web.JsonBody(min_length=3, max_length=20)],
        password: Annotated[str, web.JsonBody(min_length=8, max_length=40)],
) -> web.Response:
  # write you business code here
  # ...
  return web.Response()


app = web.Application()
app.add_routes([web.post('/hello/{path_param}', hello_handler)])
```
```python
# defining request attributes as schema 🌕
from pydantic import BaseModel, Field

class PathRequestSchema(BaseModel):
    path_param: str

class HeaderRequestSchema(BaseModel):
    host: str = Field(alias='Host')
    user_agent: str = Field(alias='User-Agent')

class CookieRequestSchema(BaseModel):
    user_cookie1: str = Field(alias='UserCookie1')
    user_cookie2: str = Field(alias='UserCookie2')

class QueryRequestSchema(BaseModel):
    user_cookie1: str = Field(alias='UserQueryParam1')
    user_cookie2: str = Field(alias='UserQueryParam1')

class BodyRequestSchema(BaseModel):
    username: str = Field(min_length=3, max_length=20)
    password: str = Field(min_length=8, max_length=40)

async def hello_handler(
        request: web.Request,
        path: Annotated[PathRequestSchema, web.PathSchema],
        headers: Annotated[HeaderRequestSchema, web.HeaderSchema],
        cookies: Annotated[CookieRequestSchema, web.Cookie],
        query: Annotated[QueryRequestSchema, web.QuerySchema],
        body: Annotated[BodyRequestSchema, web.JsonBodySchema],
) -> web.Response:

```

```python
# defining request attributes as raw 🌑
async def hello_handler(
        request: web.Request,
        path: Annotated[Dict[str, str], web.PathRaw],
        headers: Annotated[Dict[str, str], web.HeaderRaw],
        cookies: Annotated[Dict[str, str], web.CookieRaw],
        query: Annotated[Dict[str, str], web.QueryRaw],
        body: Annotated[Dict[str, Any], web.JsonBodyRaw],
) -> web.Response:
```

```python
# also you may to combine 🌒 🌕 🌑
async def hello_handler(
        request: web.Request,
        path_param: Annotated[str, web.Path],
        headers: Annotated[Dict[str, str], web.HeaderRaw],
        body: Annotated[BodyRequestSchema, web.JsonBodySchema],
) -> web.Response:
```

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "rAPIdy",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8,<4.0",
    "maintainer_email": "",
    "keywords": "rAPIdy,aiohttp,pydantic,api,fast,http server,Daniil Grois",
    "author": "Daniil Grois",
    "author_email": "daniil.grois@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/14/47/4c8e79afe6c95ff0fbec9ff0537698ea7eeafb3cecdc4ec82ac674430c3a/rapidy-0.1.1.tar.gz",
    "platform": null,
    "description": "\n# rAPIdy \ud83d\udcae\n**write quickly** \ud83d\ude80 **write beautifully** \ud83c\udf38\n\n<a href=\"https://github.com/daniil-grois/rAPIdy\">rAPIdy<a/> is a minimalistic, asynchronous, fast web framework based in aiohttp and pydantic.\n\n```\npip install rapidy\n```\n\nKey Features:\n* \u270f\ufe0f easy to write and read code\n* \ud83d\udcd4 <a href=\"https://github.com/pydantic/pydantic\">pydantic<a/> native support -> **yes** we support **V**1\ufe0f\u20e3 and **V**2\ufe0f\u20e3\u2757\n* \ud83d\ude80 <a href=\"https://github.com/aio-libs/aiohttp\">aiohttp<a/> based and native features support - aiohttp one of the fastest and most productive HTTP servers\n* \ud83d\udce4 convenient support for basic types of incoming data extraction\n\n## Quickstart\n\n### Create endpoint using RouteTableDef\n\nrAPIdy inherits the basic functionality of aiohttp <a href=\"https://docs.aiohttp.org/en/stable/web_quickstart.html\">quickstart</a>\n\n```python\nfrom rapidy import web\nfrom typing_extensions import Annotated\n\nroutes = web.RouteTableDef()\n\n\n@routes.get('/hello')\nasync def hello(\n        request: web.Request,\n        username: Annotated[str, web.JsonBody(min_length=3, max_length=20)],\n        password: Annotated[str, web.JsonBody(min_length=8, max_length=40)],\n) -> web.Response:\n  # write you business code here\n  return web.json_response({'username': username, 'password': password})\n\n\napp = web.Application()\napp.add_routes(routes)\n\nif __name__ == '__main__':\n  web.run_app(app, port=8000)\n```\n\n### Create endpoint using web.<method_name>\n\n```python\nfrom rapidy import web\nfrom typing_extensions import Annotated\n\n\nasync def hello(\n        request: web.Request,\n        username: Annotated[str, web.JsonBody(min_length=3, max_length=20)],\n        password: Annotated[str, web.JsonBody(min_length=8, max_length=40)],\n) -> web.Response:\n  # write you business code here\n  return web.json_response({'username': username, 'password': password})\n\n\napp = web.Application()\napp.add_routes([web.post('/hello', hello)])\n\nif __name__ == '__main__':\n  web.run_app(app, port=8000)\n```\n\n### Create endpoint using web.view\n\n```python\nfrom rapidy import web\nfrom typing_extensions import Annotated\n\n\nclass Handler(web.View):\n  async def post(\n          self,\n          username: Annotated[str, web.JsonBody(min_length=3, max_length=20)],\n          password: Annotated[str, web.JsonBody(min_length=8, max_length=40)],\n  ) -> web.Response:\n    # write you business code here\n    return web.json_response({'username': username, 'password': password})\n\n\napp = web.Application()\napp.add_routes([web.view('/hello', Handler)])\n\nif __name__ == '__main__':\n  web.run_app(app, port=8000)\n```\n\n## Pydantic native support\n\n```python\nfrom rapidy import web\nfrom typing_extensions import Annotated\n\n\nasync def hello_handler(\n        request: web.Request,\n        username: Annotated[str, web.JsonBody(min_length=3, max_length=20)],\n        password: Annotated[str, web.JsonBody(min_length=8, max_length=40)],\n) -> web.Response:\n  # write you business code here\n  return web.json_response({'username': username, 'password': password})\n\n\napp = web.Application()\napp.add_routes([web.post('/hello', hello_handler)])\nweb.run_app(app, port=8000)\n```\n\u2705\u2705\u2705 Success request validation \u2705\u2705\u2705\n```\ncurl -X POST \\\n-H \"Content-Type: application/json\" -d '{\"username\": \"Max\", \"password\": \"myAwesomePass\"}' -v \\\nhttp://127.0.0.1:8000/hello\n\n< HTTP/1.1 200 OK ... {\"username\": \"Max\", \"password\": \"myAwesomePass\"}\n```\n\n\u274c\u274c\u274c Request validation failure \u274c\u274c\u274c\n\n```\ncurl -X POST \\\n-H \"Content-Type: application/json\" -d '{\"username\": \"M\", \"password\": \"m\"}' -v \\\nhttp://127.0.0.1:8000/hello\n\n< HTTP/1.1 422 Unprocessable Entity ...\n{\n    \"errors\": [\n        {\n            \"loc\": [\"body\", \"username\"],\n            \"type\": \"string_too_short\",\n            \"msg\": \"String should have at least 3 characters\",\n            \"ctx\": {\"min_length\": 3}\n        },\n        {\n            \"type\": \"string_too_short\",\n            \"loc\": [\"body\", \"password\"],\n            \"msg\": \"String should have at least 8 characters\",\n            \"ctx\": {\"min_length\": 8}\n        }\n    ]\n}\n\n```\n\n## Choose your path\n\n* You can create APIs the way you want.\n* **rAPIdy** supports 3 basic types for defining incoming parameters\n  * \ud83c\udf12 param\n    * Path\n    * Header\n    * Cookie\n    * Query\n    * BodyJson\n    * FormDataBody\n    * MultipartBody\n  * \ud83c\udf15 schema\n    * PathSchema\n    * HeaderSchema\n    * CookieSchema\n    * QuerySchema\n    * BodyJsonSchema\n    * FormDataBodySchema\n    * MultipartBodySchema\n  * \ud83c\udf11 raw data (no validate with pydantic)\n    * PathRaw - **Dict[str, str]**\n    * HeaderRaw - **Dict[str, str]**\n    * CookieRaw - **Dict[str, str]**\n    * QueryRaw - **Dict[str, str]**\n    * BodyJsonRaw - **Dict[str, Any]**\n    * FormDataBodyRaw - **Dict[str, Any]**\n    * MultipartBodyRaw - **Dict[str, Any]**\n    * TextBody - **str**\n    * BytesBody - **bytes**\n    * StreamBody - **aiohttp.streams.StreamReader**\n\n```python\n# defining request attributes as param \ud83c\udf12\nfrom rapidy import web\nfrom typing_extensions import Annotated\n\n\nasync def hello_handler(\n        request: web.Request,\n        # path params\n        path_param: Annotated[str, web.Path],\n        # headers\n        host: Annotated[str, web.Header(alias='Host')],\n        user_agent: Annotated[str, web.Header(alias='User-Agent')],\n        # cookie\n        user_cookie1: Annotated[str, web.Cookie(alias='UserCookie1')],\n        user_cookie2: Annotated[str, web.Cookie(alias='UserCookie2')],\n        # query params\n        user_param1: Annotated[str, web.Query(alias='UserQueryParam1')],\n        user_param2: Annotated[str, web.Cookie(alias='UserQueryParam2')],\n        # body\n        username: Annotated[str, web.JsonBody(min_length=3, max_length=20)],\n        password: Annotated[str, web.JsonBody(min_length=8, max_length=40)],\n) -> web.Response:\n  # write you business code here\n  # ...\n  return web.Response()\n\n\napp = web.Application()\napp.add_routes([web.post('/hello/{path_param}', hello_handler)])\n```\n```python\n# defining request attributes as schema \ud83c\udf15\nfrom pydantic import BaseModel, Field\n\nclass PathRequestSchema(BaseModel):\n    path_param: str\n\nclass HeaderRequestSchema(BaseModel):\n    host: str = Field(alias='Host')\n    user_agent: str = Field(alias='User-Agent')\n\nclass CookieRequestSchema(BaseModel):\n    user_cookie1: str = Field(alias='UserCookie1')\n    user_cookie2: str = Field(alias='UserCookie2')\n\nclass QueryRequestSchema(BaseModel):\n    user_cookie1: str = Field(alias='UserQueryParam1')\n    user_cookie2: str = Field(alias='UserQueryParam1')\n\nclass BodyRequestSchema(BaseModel):\n    username: str = Field(min_length=3, max_length=20)\n    password: str = Field(min_length=8, max_length=40)\n\nasync def hello_handler(\n        request: web.Request,\n        path: Annotated[PathRequestSchema, web.PathSchema],\n        headers: Annotated[HeaderRequestSchema, web.HeaderSchema],\n        cookies: Annotated[CookieRequestSchema, web.Cookie],\n        query: Annotated[QueryRequestSchema, web.QuerySchema],\n        body: Annotated[BodyRequestSchema, web.JsonBodySchema],\n) -> web.Response:\n\n```\n\n```python\n# defining request attributes as raw \ud83c\udf11\nasync def hello_handler(\n        request: web.Request,\n        path: Annotated[Dict[str, str], web.PathRaw],\n        headers: Annotated[Dict[str, str], web.HeaderRaw],\n        cookies: Annotated[Dict[str, str], web.CookieRaw],\n        query: Annotated[Dict[str, str], web.QueryRaw],\n        body: Annotated[Dict[str, Any], web.JsonBodyRaw],\n) -> web.Response:\n```\n\n```python\n# also you may to combine \ud83c\udf12 \ud83c\udf15 \ud83c\udf11\nasync def hello_handler(\n        request: web.Request,\n        path_param: Annotated[str, web.Path],\n        headers: Annotated[Dict[str, str], web.HeaderRaw],\n        body: Annotated[BodyRequestSchema, web.JsonBodySchema],\n) -> web.Response:\n```\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "rAPIdy - write quickly - write beautifully",
    "version": "0.1.1",
    "project_urls": null,
    "split_keywords": [
        "rapidy",
        "aiohttp",
        "pydantic",
        "api",
        "fast",
        "http server",
        "daniil grois"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "6fe20e357e32661ed6fe7f23185f72e8c45a40deffa7aea34c2a1c2cf23543c1",
                "md5": "611b4afe6d646983e78fa576c2e52166",
                "sha256": "238b7b83210c4eb54b17aa7a037eeb4f013aa0bb5d5ddfc29be7bc4f5d37a9c1"
            },
            "downloads": -1,
            "filename": "rapidy-0.1.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "611b4afe6d646983e78fa576c2e52166",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8,<4.0",
            "size": 25910,
            "upload_time": "2024-02-29T16:46:32",
            "upload_time_iso_8601": "2024-02-29T16:46:32.082116Z",
            "url": "https://files.pythonhosted.org/packages/6f/e2/0e357e32661ed6fe7f23185f72e8c45a40deffa7aea34c2a1c2cf23543c1/rapidy-0.1.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "14474c8e79afe6c95ff0fbec9ff0537698ea7eeafb3cecdc4ec82ac674430c3a",
                "md5": "9cc7eca82a76fdd6365cdcb09df894fb",
                "sha256": "ec8542a70bfad58627b961e66c4cb5e51844c5b0707940c1fd59b4116ac3328c"
            },
            "downloads": -1,
            "filename": "rapidy-0.1.1.tar.gz",
            "has_sig": false,
            "md5_digest": "9cc7eca82a76fdd6365cdcb09df894fb",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8,<4.0",
            "size": 22042,
            "upload_time": "2024-02-29T16:46:33",
            "upload_time_iso_8601": "2024-02-29T16:46:33.856764Z",
            "url": "https://files.pythonhosted.org/packages/14/47/4c8e79afe6c95ff0fbec9ff0537698ea7eeafb3cecdc4ec82ac674430c3a/rapidy-0.1.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-02-29 16:46:33",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "rapidy"
}
        
Elapsed time: 0.19853s