A small rest framework
Project description
restfy
A small rest framework.
Instalation
pip install restfy
Usage
Minimal usage
A basic Restfy application is showed below.
from restfy import Application, Server, Request, Response
app = Application()
@app.post('/')
async def handler(request: Request) -> Response:
ret = request.data
return Response(ret)
server = Server(app)
server.run()
This code fragment sets up a basic web application using your asynchronous web application framework. It defines a route for a POST request at the root URL and returns a response with the request data. The server is then started to handle incoming requests.
In this code, the restfy module is imported, and the necessary classes Application, Server, Request, and Response are imported from it.
An instance of the Application class is created and assigned to the variable app. This class represents the restfy application framework itself.
The @app.post('/')
decorator is used to define a route for the HTTP POST method at the root URL ("/") of the application. When a POST request is made to this URL, the handler function will be called.
The handler function is an asynchronous function that takes a request parameter of type Request. It creates a Response object with a data and returns it.
An instance of the Server class is created, passing the app object as a parameter to associate the server with the application.
Finally, the run() method is called on the server object, which starts the server and makes it listen for incoming requests.
The routes also can be added by using .add_route(path, handler, method)
application method.
from restfy import Application, Server, Response, Request
async def handler(request: Request) -> Response:
data = f'{request.method}: {request.url}'
return Response(data)
app = Application()
app.add_route('/', handler, method='GET')
...
Adding route by router decorator
For applications with a great number of routes is necessary a better modules organization. To help in this process, Restfy has a class to manager the routes, Router class.
The Router class is similar to Application class to register routes. Then, a cluster of routes can be created as necessary.
# servers.py
from restfy import Router
router = Router()
@router.get('')
async def get_servers_list():
ret = []
return ret
@router.post('')
async def create_new_server():
...
return {}
...
# application.py
from restfy import Application
from .servers import router as servers
app = Application()
app.register_router('/servers', servers)
...
As we can see, the routes are defined on other file by a Route instance.
The app object registry this through .register_router(path, router)
.
With this approach, several routes can be registered with different routes.
Receiving data and args from request object
The information can be passed by path variables, query_string parameters, request body and request headers.
Below, is showed a condensed example how to that information are distributed inside Request object.
...
@router.put('/servers/{key}')
async def handler(
request: Request,
key: int
) -> Response:
headers: dict = request.headers # request headers
...
# Body HTTP request
body: bytes = request.body # The raw binary request body.
dada: dict | list | None = request.data # A deserialized body.
...
# The path variables
args: dict = request.path_args # Complete variables
vars: dict = request.vars # Variables not explicit used by function
...
# The query_string parameters
query: dict = request.query_args # Complete
params: dict = request.params # Incomplete
...
return Response([])
...
If you need a more explict variable declaration, you can declare it as a function parameter. Restfy will identify this value on Request path_args or query_args and set it. The query_args and path_args will not be affected by the Request params and vars will be. That attributes hold the values are not used as function parameter. Then, in the fragment above, the path_args will have the key value and the vars will be empty because key value is setted as a funcion parameter.
The Request try parse the body bytes to data based on its content type.
For example, if the request content type is a application/json
, the data will set by json format.
Returning data
If we are creating a server, it a fact we want return some data. It can be done by a Response instance object passing data attribute and optionality, the status and headers. In addition, we can just return a value that Restfy will try to create a Response object instance based on value type.
The return also can be a tuple with value and the status code.
That shortcuts are very useful for most common situations by when the data are a file body, we need create a Response instance with the correct content type.
In the future Restfy release, probably will bring exclusive Response objects but will not cover all cases.
from restfy.http import Response, Request
...
async def handler(request: Request, pk: int) -> Response:
data = f'<b>restfy: pk {pk}</b>'
headers = {
'Content-Type': 'text/html'
}
return Response(data, status=400, headers=headers)
...
async def handler_other(request: Request, pk: int) -> Response:
data = f'<b>restfy: pk {pk}</b>'
return Response(data, status=400, content_type='text/html')
...
Middlewares
Restfy uses middleware creating a class with .exec() method. The parameter request must be passed into exec method.
The Application has the method .register_middleware() to register middlewares. The register order is the same order of execution.
from restfy import Application, Middleware
class DefaultMiddleware(Middleware):
async def exec(self, request):
# Do something with request object
...
response = await self.forward(request)
...
# Do something with response object
return response
app = Application()
app.register_middleware(DefaultMiddleware)
HTTP client requests
With http module, you can do asynchronous requests to other services. The most simple request can be seen below.
from restfy import http
...
res = await http.get('https://someserver.api/endpoint')
print(res.status)
# 200
In addition to the get function, others functions are available like post(), put(), delete() and patch(). If other request method are necessary, we can use request() function passing method param. The next example shows a more complex example.
from restfy import http
data = {
'name': 'Nick',
'surname': 'Lauda'
}
headers = {
'Content-Type': 'application/json'
}
url = 'https://someserver.api/endpoint'
res = await http.post(url=url, data=data, headers=headers)
print(res.status)
# 200
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file restfy-0.4.1.tar.gz
.
File metadata
- Download URL: restfy-0.4.1.tar.gz
- Upload date:
- Size: 13.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.5.1 CPython/3.10.6 Linux/5.19.0-43-generic
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | ad3780162cf63fd4dae444fa743ec271b1fe42e7c27d4ec876c4d6ca1d82ba72 |
|
MD5 | 7e0c5bb2530c7b9f794adcf1e3f71793 |
|
BLAKE2b-256 | 336306b9f14218ac8bc0dc6ab4687fe94a3f4e92096c6950213885aa0f98bc53 |
File details
Details for the file restfy-0.4.1-py3-none-any.whl
.
File metadata
- Download URL: restfy-0.4.1-py3-none-any.whl
- Upload date:
- Size: 14.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.5.1 CPython/3.10.6 Linux/5.19.0-43-generic
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | e85e07d7082522c946fefd38201a51746a2221df8aaa6705561105322addd606 |
|
MD5 | a8cb5f01a2daa6f94a67fda3f05b0294 |
|
BLAKE2b-256 | fb3af604c1fd97a0eabaa7c70e899f2219e482017fe2302d02ebef8f90aa3d55 |