Lightweight web framework

If you’re a Python developer you may have used popular web frameworks like Flask or Django. These projects can be complex and require many third-party dependencies to run. What’s interesting about Python is that it’s standard library actually already includes almost everything you need for a web framework. It’s just not that well documented.

For example: there’s code that will process a HTTP request, parse URLs, and more in the standard library. What I’ve done is wrap these components in an interface similar to flask and other web frameworks with P2PD for the networking. The result is a light-weight, async web framework, that properly supports multiple interfaces, address families, and transports.

from p2pd import *

class CustomServer(RESTD):
    @RESTD.GET()
    async def show_index(self, v, pipe):
        print(v)
        #
        # text/html response.
        return "hello"
    #
    @RESTD.POST(["proxies"], ["toxics"])
    async def add_new_toxic(self, v, pipe):
        """
        Matches /proxies/.*/toxics/.*
        and names the value at 
        v['proxies'] and v['toxics']
        respectively.
        """
        #
        # Demonstrates a JSON response.
        return {
            "status": "success"
        }
    #
    @RESTD.DELETE(["proxies"], ["toxics"])
    async def del_new_toxic(self, v, pipe):
        # Application/octet-stream response.
        return b""

async def example():
    i = await Interface().start_local()
    server = CustomServer()
    await server.listen_all(
        [
            await i.route(IP4),
            await i.route(IP4).bind(ips="127.0.0.1")
        ],
        [60322],
        [TCP, UDP],
    )
    #
    """
    Feel free to add a while: sleep
    then test it with CURL or something...
    """
    #
    await server.close()

if __name__ == '__main__':
    async_test(example)

As you can see functions in the web framework are decorated with a REST method. They use async await, a pipe back to the client, and introduce a v parameter with access to relevant HTTP information. The structure of v looks like this:

{
    # class to process HTTP request
    # see req.url for $_GET params.
    'req': 'parsehttprequest object',
    #
    # named REST path
    'name': {},
    #
    # unnamed positional items
    'pos': {}, # 0, 1, ... n -> value
    #
    # client remote address info
    'client': ('192.168.8.158', 60085),
    #
    # $_POST data -- not multiple fields.
    'body': b''
}

When you define your REST methods you can do so with a list of named arguments. These highlight what is added by name in a URL. For example: ‘/cat/meow’ could be highlighted with @RESTD.GET([“cat”]) and ‘name’ would be {‘cat’: ‘meow’}. Values in the URL path that aren’t matched by the named path are added to the pos dictionary (at keys 0 … to len - 1.)

The field ‘body’ is the binary content of a POST request. While req is a class that has processed the HTTP request of the client. There’s useful fields in that class for debugging server code.