AsyncAPY - Getting started

Installing

Right now, the package is not available on PyPi because some custom dependencies need to be documented and published to the index before AsyncAPY can be succesfully installed via pip. In the meanwhile, you can run the following command in your terminal/shell (assuming pip and git are already installed):

python3 -m pip install --user git+https://github.com/intellivoid/AsyncAPY

This will install AsyncAPY and its dependencies in your system

Note: On Windows systems, unless you are using PowerShell, you may need to replace python3 with py or py3 for the commands to work, assuming you added it to PYTHONPATH when installed Python.

Hello, world!

Let’s write our very first API server with AsyncAPY, an echo server.

An echo server is fairly simple, it always replies with the same request that it got from the client

from AsyncAPY import Server

server = Server(addr='0.0.0.0',
                port=1500
               )

async def echo_server(client, packet):
    print(f"Hello world from {client}!")
    print(f"Echoing back {packet}...")
    await client.send(packet)
    await client.close()

server.register_handler(echo_server)   # Register our handler

server.start()    # Start the server

Save this script into a file named example.py.

What happens if we send a packet to our new, shiny, echo server? Let’s try to use the testing client to send a packet to our server: create a new empty file, name it testclient.py and paste the following

import AsyncAPY.defaultclient


client = defaultclient.Client("0.0.0.0", 1500, tls=False)
enc = 'json'
client.connect()
client.send({"test": 1}, encoding=enc)
response = client.receive_all()
print(response)

Now open two terminal windows, run example.py and then testclient.py, your server output should look like the following:

[INFO] 10/02/2020 16:39:35 PM  {Client handler} New session started, UUID is 7fd5fab0-5393-44ec-a75d-fa4f2c7e4562

[DEBUG] 10/02/2020 16:39:35 PM (7fd5fab0-5393-44ec-a75d-fa4f2c7e4562) {Client handler} Expected stream length is 11

[DEBUG] 10/02/2020 16:39:35 PM (7fd5fab0-5393-44ec-a75d-fa4f2c7e4562) {API Parser} Protocol-Version is V2, Content-Encoding is json

[DEBUG] 10/02/2020 16:39:35 PM (7fd5fab0-5393-44ec-a75d-fa4f2c7e4562) {API Parser} Checking group 0

[DEBUG] 10/02/2020 16:39:35 PM (7fd5fab0-5393-44ec-a75d-fa4f2c7e4562) {API Parser} Calling 'echo_server' in group 0

Hello world from Client(127.0.0.1)!

Echoing back Packet({"test": 1})...

[DEBUG] 10/02/2020 16:39:35 PM (7fd5fab0-5393-44ec-a75d-fa4f2c7e4562) {Response handler} Sending response to client

[DEBUG] 10/02/2020 16:39:35 PM (7fd5fab0-5393-44ec-a75d-fa4f2c7e4562) {Response Handler} Response sent

[INFO] 10/02/2020 16:39:36 PM (7fd5fab0-5393-44ec-a75d-fa4f2c7e4562) {Client handler} The connection was closed

while your client output will look like this:

b'\x00\x00\x00\r\x16\x00{"test": 1}'

As you can see, we got the same JSON encoded packet that we sent!

Filters

You can allow only a subset of packet/client pair to reach your handler, see here to know more.

Filters can be applied to a handler by passing one or more Filter objects to the Server.register_handler().

An example of a filtered handler can be found in our dedicated examples section

If you have issues with filters, try reading our FAQ on this topic

Using the decorators

Decorators are a nicer way to add handlers to your server. The line Server.register_handler() can be also written as follows:

@server.add_handler()
async def your_handler(c, p):
    ...

The decorator behaves the same as Server.register_handler and take the filter object(s) and the group identifier as optional parameters.

Groups

The way AsyncAPY handles incoming requests has been specifically designed to be simple yet effective.

If you register two or more handlers with conflicting/overlapping filters, only the first one that was registered will be executed.

To handle the same request more than once, you need to register the handler in a different handlers group, like in the following example:

from asyncapy import Server

server = Server(addr="127.0.0.1", port=1500)


@server.add_handler()
async def echo_server(client, packet):
    print(f"Hello world from {client}!")
    print(f"Echoing back {packet}...")
    await client.send(packet)
    await client.close()


@server.add_handler(group=-1)
async def echo_server_2(client, packet):
    print(f"Hello world from {client} inside a group!")
    print(f"Echoing back {packet}...")
    await client.send(packet)
    # packet.stop_propagation()  # This would prevent the packet from being forwarded to the next handler


server.start()

The group parameter defaults to 0, the lower this number, the higher will be the position of the handler in the queue. In the example above, group equals -1, that is lower than 0 and therefore causes that handler to execute first. You could have also set it to 1 (or any other value greather than 0) to make it execute last instead.