fastipy


Namefastipy JSON
Version 1.5.4 PyPI version JSON
download
home_pagehttps://github.com/Bielgomes/Fastipy
SummaryFastipy is a fast and easy-to-use open source Python library for developing RESTful APIs. Inspired by the FastAPI and Fastify syntax and powered by uvicorn ASGI web server.
upload_time2024-11-02 05:49:05
maintainerNone
docs_urlNone
authorBielgomes
requires_python<4.0.0,>=3.10.11
licenseGPLv3
keywords restful api asgi fastapi fastipy web server
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Fastipy

<div>
  <img src="https://i.imgur.com/KCi8IUS.png">
</div>

[![CI](https://github.com/Bielgomes/fastipy/actions/workflows/pipeline.yaml/badge.svg)](https://github.com/Bielgomes/fastipy/actions/workflows/pipeline.yaml)
[![codecov](https://codecov.io/gh/Bielgomes/fastipy/graph/badge.svg?token=AF45LFYAP2)](https://codecov.io/gh/Bielgomes/fastipy)
[![PyPI version](https://badge.fury.io/py/fastipy.svg)](https://badge.fury.io/py/fastipy)

## What is it and what is it for

[Fastipy](https://pypi.org/project/Fastipy/) is a fast and easy-to-use open source Python library for developing RESTful APIs.

Powered by **[uvicorn](https://www.uvicorn.org/)**

## Installation

```bash
pip install fastipy
```

## Examples

### Example for GET Route with Query Params

```py
from fastipy import Fastipy, Request, Reply

app = Fastipy()

# Routes can be async or sync functions, but reply send functions are async
# The handler returns the default HTTP status code 200
@app.get("/")
def home(req: Request, _):
  # Get query params age
  age = req.query["age"]
  # Example: Recovery all persons from database with this age and print the html
  print("<h1>Retrieving all persons</h1><ul><li>A Person</li></ul>")
```

### Example for GET Route with Params, CORS and multiple methods

```py
from fastipy import Fastipy, Request, Reply

app = Fastipy().cors()

@app.get("/user/:id")
@app.post("/user/:id")
async def getUser(req: Request, reply: Reply):
  # get users from database
  for i in users:
    if i["id"] == req.params["id"]:
      # All response functions are asynchronous
      return await reply.send(i)

  await reply.send_code(404)
```

### Example for POST Route with Body

```py
from fastipy import Fastipy, Request, Reply

app = Fastipy()

@app.post("/user")
async def createUser(req: Request, reply: Reply):
  user = req.body.json
  # Save user in database
  await reply.code(201).send("Created")
```

### Example for PUT Route with Body

```py
from fastipy import Fastipy, Request, Reply

app = Fastipy()

@app.put("/user")
async def createUser(req: Request, reply: Reply):
  user = req.body.json
  # Update user in database
  await reply.type("text/html").code(201).send("<h1>Created</h1>")
```

### Example for GET Route with file stream

```py
from fastipy import Fastipy, Request, Reply

app = Fastipy()

@app.get("/stream")
async def streamFile(_, reply: Reply):
  # It could be an asynchronous generator
  def generator():
    with open("file.txt") as f:
        for line in f:
            yield line

  await reply.send(generator())
```

### Adding custom serializer to Reply send

```py
from fastipy import Fastipy, Request, Reply

app = Fastipy()

app.add_serializer(
    validation=lambda data: isinstance(data, str),
    serializer=lambda data: ("application/json", json.dumps({"error": data})),
)

@app.get("/")
async def customSerializer(_, reply: Reply):
    await reply.code(404).send("Field not found")
```

### Running

Running Fastipy application in development is easy

```py
import uvicorn

if __name__ == "__main__":
  # main:app indicates the FILE:VARIABLE

  # The file is the main file where Fastipy() is instantiated
  # The variable is the name of the variable that contains the instance of Fastipy()

  # You can find more configurations here https://www.uvicorn.org/

  # set reload to True for automatic reloading!
  uvicorn.run("main:app", log_level="debug", port=8000, reload=True, loop="asyncio")
```

### See more examples in **[examples](https://github.com/Bielgomes/Fastipy/tree/main/examples)** folder

## Creating plugins

```py
# chat.py
from fastipy import FastipyInstance, Reply

# Plugins can be asynchronous or synchronized functions
# Plugins have access to the main instance, which means they can use all of Fastipy's functions
def chatRoutes(app: FastipyInstance, options: dict):
  @app.get("/")
  async def index(_, reply: Reply):
    await reply.send_code(200)

  @app.get("/chat")
  async def test(_, reply: Reply):
    await reply.send_code(200)
```

```py
# message.py
from fastipy import FastipyInstance, Reply

async def messageRoutes(app: FastipyInstance, options: dict):
  @message.get("/")
  async def index(_, reply: Reply):
    await reply.send_code(200)

  @message.get("/message")
  async def test(_, reply: Reply):
    await reply.send_code(200)

  app.name("custom plugin name")
```

```py
# main.py
from fastipy import Fastipy

from message import messageRoutes
from chat import chatRoutes

app = Fastipy().cors()

app.register(messageRoutes, {"prefix": "/message"})
app.register(chatRoutes, {"prefix": "/chat"})
```

## Hooks

```py
from fastipy import Fastipy, Request, Reply

app = Fastipy()

# The preHandler hook is called before the request handler
@app.hook("preHandler")
def preHandler(req: Request, reply: Reply):
  print("onRequest hook")

# The onRequest hook is called when the request is handled
@app.hook("onRequest")
def onRequest(req: Request, reply: Reply):
  print("onRequest hook")

# The onResponse hook is called when the reply sends a response
@app.hook("onResponse")
def onResponse(req: Request, reply: Reply):
  print("onResponse hook")

# The onError hook is called when an error occurs
@app.hook("onError")
def onError(error: Exception, req: Request, reply: Reply):
  print(f"onError hook exception: {error}")

# A hook will only be linked to a route if its declaration precedes the route
# The order of hooks of the same type is important
@app.get("/")
async def index(_, reply: Reply):
  await reply.send_code(200)
```

## End to End tests

```py
# See more in https://www.starlette.io/testclient/
from fastipy import TestClient
from main import app

client = TestClient(app)

response = client.post("/")
assert response.status_code == 200
assert response.text == "Hello World"
```

# Application Deploy

For production deployment, please refer to this **[uvicorn guide](https://www.uvicorn.org/deployment/)**.

# Change Log

## Development Version 1.5.4

### Todo

### Added

- [X] CI with Github Actions.
- [X] Code Coverage with Codecov.

### Changed

- [X] Change the routes handler to use the Raw Path instead of the Path (This Change allow the use of %20 %2F and other special characters in the path).
- [X] Improve functionality to handle asynchronous functions in synchronous environments (This change probably fix Memory Leak in the Fastipy).

### Fixed

- [X] Fix the bug in the search route where special characters are not being URL-escaped.

# Contributors

<a href="https://github.com/Bielgomes/Fastipy/graphs/contributors">
  <img src="https://contrib.rocks/image?repo=Bielgomes/Fastipy"/>
</a>

## How to Contributing

Open pull request

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/Bielgomes/Fastipy",
    "name": "fastipy",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0.0,>=3.10.11",
    "maintainer_email": null,
    "keywords": "RESTful, API, ASGI, FastAPI, Fastipy, web server",
    "author": "Bielgomes",
    "author_email": "bielgomesdasilva@hotmail.com",
    "download_url": "https://files.pythonhosted.org/packages/aa/45/ba82180bff27c32ed5225eac7c1d7743cd8aecf4ade12396984b9d26396c/fastipy-1.5.4.tar.gz",
    "platform": null,
    "description": "# Fastipy\n\n<div>\n  <img src=\"https://i.imgur.com/KCi8IUS.png\">\n</div>\n\n[![CI](https://github.com/Bielgomes/fastipy/actions/workflows/pipeline.yaml/badge.svg)](https://github.com/Bielgomes/fastipy/actions/workflows/pipeline.yaml)\n[![codecov](https://codecov.io/gh/Bielgomes/fastipy/graph/badge.svg?token=AF45LFYAP2)](https://codecov.io/gh/Bielgomes/fastipy)\n[![PyPI version](https://badge.fury.io/py/fastipy.svg)](https://badge.fury.io/py/fastipy)\n\n## What is it and what is it for\n\n[Fastipy](https://pypi.org/project/Fastipy/) is a fast and easy-to-use open source Python library for developing RESTful APIs.\n\nPowered by **[uvicorn](https://www.uvicorn.org/)**\n\n## Installation\n\n```bash\npip install fastipy\n```\n\n## Examples\n\n### Example for GET Route with Query Params\n\n```py\nfrom fastipy import Fastipy, Request, Reply\n\napp = Fastipy()\n\n# Routes can be async or sync functions, but reply send functions are async\n# The handler returns the default HTTP status code 200\n@app.get(\"/\")\ndef home(req: Request, _):\n  # Get query params age\n  age = req.query[\"age\"]\n  # Example: Recovery all persons from database with this age and print the html\n  print(\"<h1>Retrieving all persons</h1><ul><li>A Person</li></ul>\")\n```\n\n### Example for GET Route with Params, CORS and multiple methods\n\n```py\nfrom fastipy import Fastipy, Request, Reply\n\napp = Fastipy().cors()\n\n@app.get(\"/user/:id\")\n@app.post(\"/user/:id\")\nasync def getUser(req: Request, reply: Reply):\n  # get users from database\n  for i in users:\n    if i[\"id\"] == req.params[\"id\"]:\n      # All response functions are asynchronous\n      return await reply.send(i)\n\n  await reply.send_code(404)\n```\n\n### Example for POST Route with Body\n\n```py\nfrom fastipy import Fastipy, Request, Reply\n\napp = Fastipy()\n\n@app.post(\"/user\")\nasync def createUser(req: Request, reply: Reply):\n  user = req.body.json\n  # Save user in database\n  await reply.code(201).send(\"Created\")\n```\n\n### Example for PUT Route with Body\n\n```py\nfrom fastipy import Fastipy, Request, Reply\n\napp = Fastipy()\n\n@app.put(\"/user\")\nasync def createUser(req: Request, reply: Reply):\n  user = req.body.json\n  # Update user in database\n  await reply.type(\"text/html\").code(201).send(\"<h1>Created</h1>\")\n```\n\n### Example for GET Route with file stream\n\n```py\nfrom fastipy import Fastipy, Request, Reply\n\napp = Fastipy()\n\n@app.get(\"/stream\")\nasync def streamFile(_, reply: Reply):\n  # It could be an asynchronous generator\n  def generator():\n    with open(\"file.txt\") as f:\n        for line in f:\n            yield line\n\n  await reply.send(generator())\n```\n\n### Adding custom serializer to Reply send\n\n```py\nfrom fastipy import Fastipy, Request, Reply\n\napp = Fastipy()\n\napp.add_serializer(\n    validation=lambda data: isinstance(data, str),\n    serializer=lambda data: (\"application/json\", json.dumps({\"error\": data})),\n)\n\n@app.get(\"/\")\nasync def customSerializer(_, reply: Reply):\n    await reply.code(404).send(\"Field not found\")\n```\n\n### Running\n\nRunning Fastipy application in development is easy\n\n```py\nimport uvicorn\n\nif __name__ == \"__main__\":\n  # main:app indicates the FILE:VARIABLE\n\n  # The file is the main file where Fastipy() is instantiated\n  # The variable is the name of the variable that contains the instance of Fastipy()\n\n  # You can find more configurations here https://www.uvicorn.org/\n\n  # set reload to True for automatic reloading!\n  uvicorn.run(\"main:app\", log_level=\"debug\", port=8000, reload=True, loop=\"asyncio\")\n```\n\n### See more examples in **[examples](https://github.com/Bielgomes/Fastipy/tree/main/examples)** folder\n\n## Creating plugins\n\n```py\n# chat.py\nfrom fastipy import FastipyInstance, Reply\n\n# Plugins can be asynchronous or synchronized functions\n# Plugins have access to the main instance, which means they can use all of Fastipy's functions\ndef chatRoutes(app: FastipyInstance, options: dict):\n  @app.get(\"/\")\n  async def index(_, reply: Reply):\n    await reply.send_code(200)\n\n  @app.get(\"/chat\")\n  async def test(_, reply: Reply):\n    await reply.send_code(200)\n```\n\n```py\n# message.py\nfrom fastipy import FastipyInstance, Reply\n\nasync def messageRoutes(app: FastipyInstance, options: dict):\n  @message.get(\"/\")\n  async def index(_, reply: Reply):\n    await reply.send_code(200)\n\n  @message.get(\"/message\")\n  async def test(_, reply: Reply):\n    await reply.send_code(200)\n\n  app.name(\"custom plugin name\")\n```\n\n```py\n# main.py\nfrom fastipy import Fastipy\n\nfrom message import messageRoutes\nfrom chat import chatRoutes\n\napp = Fastipy().cors()\n\napp.register(messageRoutes, {\"prefix\": \"/message\"})\napp.register(chatRoutes, {\"prefix\": \"/chat\"})\n```\n\n## Hooks\n\n```py\nfrom fastipy import Fastipy, Request, Reply\n\napp = Fastipy()\n\n# The preHandler hook is called before the request handler\n@app.hook(\"preHandler\")\ndef preHandler(req: Request, reply: Reply):\n  print(\"onRequest hook\")\n\n# The onRequest hook is called when the request is handled\n@app.hook(\"onRequest\")\ndef onRequest(req: Request, reply: Reply):\n  print(\"onRequest hook\")\n\n# The onResponse hook is called when the reply sends a response\n@app.hook(\"onResponse\")\ndef onResponse(req: Request, reply: Reply):\n  print(\"onResponse hook\")\n\n# The onError hook is called when an error occurs\n@app.hook(\"onError\")\ndef onError(error: Exception, req: Request, reply: Reply):\n  print(f\"onError hook exception: {error}\")\n\n# A hook will only be linked to a route if its declaration precedes the route\n# The order of hooks of the same type is important\n@app.get(\"/\")\nasync def index(_, reply: Reply):\n  await reply.send_code(200)\n```\n\n## End to End tests\n\n```py\n# See more in https://www.starlette.io/testclient/\nfrom fastipy import TestClient\nfrom main import app\n\nclient = TestClient(app)\n\nresponse = client.post(\"/\")\nassert response.status_code == 200\nassert response.text == \"Hello World\"\n```\n\n# Application Deploy\n\nFor production deployment, please refer to this **[uvicorn guide](https://www.uvicorn.org/deployment/)**.\n\n# Change Log\n\n## Development Version 1.5.4\n\n### Todo\n\n### Added\n\n- [X] CI with Github Actions.\n- [X] Code Coverage with Codecov.\n\n### Changed\n\n- [X] Change the routes handler to use the Raw Path instead of the Path (This Change allow the use of %20 %2F and other special characters in the path).\n- [X] Improve functionality to handle asynchronous functions in synchronous environments (This change probably fix Memory Leak in the Fastipy).\n\n### Fixed\n\n- [X] Fix the bug in the search route where special characters are not being URL-escaped.\n\n# Contributors\n\n<a href=\"https://github.com/Bielgomes/Fastipy/graphs/contributors\">\n  <img src=\"https://contrib.rocks/image?repo=Bielgomes/Fastipy\"/>\n</a>\n\n## How to Contributing\n\nOpen pull request\n",
    "bugtrack_url": null,
    "license": "GPLv3",
    "summary": "Fastipy is a fast and easy-to-use open source Python library for developing RESTful APIs. Inspired by the FastAPI and Fastify syntax and powered by uvicorn ASGI web server.",
    "version": "1.5.4",
    "project_urls": {
        "Bug tracker": "https://github.com/Bielgomes/fastipy/issues",
        "Code": "https://github.com/Bielgomes/fastipy",
        "Homepage": "https://github.com/Bielgomes/Fastipy",
        "Repository": "https://github.com/Bielgomes/Fastipy"
    },
    "split_keywords": [
        "restful",
        " api",
        " asgi",
        " fastapi",
        " fastipy",
        " web server"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "b146b52bdf8e96fb354ba2cbdb47ba672f9de515f50185b92805941b27424f0d",
                "md5": "dfb2e8baaea9029bf7df1693e8bf119b",
                "sha256": "e679b3ee54b2f87889c618991a22e1613623e170f7f7a2655cf6fdd277fa1a1b"
            },
            "downloads": -1,
            "filename": "fastipy-1.5.4-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "dfb2e8baaea9029bf7df1693e8bf119b",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0.0,>=3.10.11",
            "size": 52225,
            "upload_time": "2024-11-02T05:49:02",
            "upload_time_iso_8601": "2024-11-02T05:49:02.957604Z",
            "url": "https://files.pythonhosted.org/packages/b1/46/b52bdf8e96fb354ba2cbdb47ba672f9de515f50185b92805941b27424f0d/fastipy-1.5.4-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "aa45ba82180bff27c32ed5225eac7c1d7743cd8aecf4ade12396984b9d26396c",
                "md5": "fa2b2b7ed716bb7ba307a8a1099f5b7f",
                "sha256": "6bcda22b54f1548b97026eb7c98954a354e96531215206b7ead738af831433ec"
            },
            "downloads": -1,
            "filename": "fastipy-1.5.4.tar.gz",
            "has_sig": false,
            "md5_digest": "fa2b2b7ed716bb7ba307a8a1099f5b7f",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0.0,>=3.10.11",
            "size": 40600,
            "upload_time": "2024-11-02T05:49:05",
            "upload_time_iso_8601": "2024-11-02T05:49:05.035849Z",
            "url": "https://files.pythonhosted.org/packages/aa/45/ba82180bff27c32ed5225eac7c1d7743cd8aecf4ade12396984b9d26396c/fastipy-1.5.4.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-11-02 05:49:05",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "Bielgomes",
    "github_project": "Fastipy",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "fastipy"
}
        
Elapsed time: 0.37398s