You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Most of the server examples in the documentation are based on a somewhat restrictive pattern of running an HTTP[S] server largely in isolation, with no easy way to have it interacting with other components.
This leaves a huge gap for real world usage. In countless cases, developers want to implement a web server, but also connect it to other clients and/or servers and/or data sources.
Developers usually don't want to be caught in a pattern where the web server is the "star attraction", and difficult to connect to other elements. They'd rather have the web server running in and around numerous elements, and able to freely exchange data and control with them.
I've written an example (see section below) for how to make aiohttp easier to integrate with other asyncio elements.
Describe the solution you'd like
I recommend the documentation be updated to include an example, such as what I've provided below, of how to run an HTTP server in a way that makes it very simple to integrate with other program elements running in the asyncio environment.
This will help other developers to incorporate aiohttp-based servers in with their other work, much more easily and quickly, than digging through the aiohttp code to figure out how to adapt it to their patterns.
Describe alternatives you've considered
Here is my implementation of a very minimal server. Feel free to use it verbatim, or with adaptations, in the aiohttp documentation. The focus for this demo is making it very trivial to integrate with other asyncio elements, and support a broader range of programming patterns.
import aiohttp, aiohttp.web
async def runLocalNanoServer(
*,
port,
handler,
userData=None,
client_max_size=65536,
):
"""
Given a listen port, and a single handler coroutine function, run an absolutely
minimal web server serving from that port
:param port: TCP port to listen on
:param handler: a coroutine which gets called with (req, ctx) when
a request is received
:param userData: optional, an object to pass to the handler to help it discern from
different concurrent executions
:return: nothing
"""
# first set up and configure the server
ctx = {
'user': userData,
'port': port,
}
# ensure that inbound requests result in a call to the handler function,
# passing both the aiohttp Request, as well as a 'context' dict, containing
# all the objects involved in creating/running this server, as well as whatever userData
# object was passed in
def wrapHandler(handler):
async def call_handler(req, *args, **kw):
result = await handler(req, ctx)
return result
return call_handler
# process starts with creating an abstract 'Application' object, and adding
# routes to handle the request methods and URLs
app = ctx['app'] = aiohttp.web.Application(client_max_size=client_max_size)
# wrap the given handler function, then assign it into the app as 2 routes,
# one for no URI, other for full wildcard URLs
hdlrWrapped = wrapHandler(handler)
app.router.add_route('*', '', wrapHandler(handler))
app.router.add_route('*', '/{tail:.*}', wrapHandler(handler))
# build the server and get it ready, deliberately hardwired to localhost to avoid
# presenting an attack surface
runner = ctx['runner'] = aiohttp.web.AppRunner(app)
await runner.setup()
site = ctx['site'] = aiohttp.web.TCPSite(runner, '127.0.0.1', port, ssl_context=None)
await site.start()
server = ctx['server'] = runner.server
# now run it by launching the low-level asyncio server run method
outcome = await site._server.serve_forever()
return
async def runNanoServer():
"""
Now, an equally minimal example of launching/running this minimal server
"""
# ensure each hit returns different data
seq = [0]
# absolutely minimal handler
async def hdlr(req, ctx):
# when this handler is called, it has access to all the internals, plus the original
# userData. It's up to the handler to dive into the Request object to get everything it needs.
# Based on this, it's possible to put objects and/or callable methods into the 'userData' value
# of the 'ctx' object we receive here
resp = f"seq={seq[0]}"
seq[0] += 1
return aiohttp.web.Response(text=resp)
# now run the server
await runLocalNanoServer(
port=1234,
handler=hdlr,
)
def main():
asyncio.run(runNanoServer())
print("main finished")
if __name__ == '__main__':
main()
Related component
Server
Additional context
No response
Code of Conduct
I agree to follow the aio-libs Code of Conduct
The text was updated successfully, but these errors were encountered:
I'm not very clear on what this is trying to achieve. I don't see any integration, just some almost monkey-patching of handlers to add an extra parameter. I'd highly discourage that approach; if you need those things in every handler, just add it to the Application object (https://docs.aiohttp.org/en/stable/web_advanced.html#data-sharing-aka-no-singletons-please).
I see 2 ways that aiohttp should be run. The first is with the web app being the main runner of the application, and any other components being initialised off of it. This is probably the right approach 95-99% of the time. Documentation to help users run these components correctly is at: https://docs.aiohttp.org/en/stable/web_advanced.html#complex-applications
The second approach is for more complex applications where the web app is a smaller component (e.g. homeassistant, which is basically an OS), in which case the runners should be used directly, and the user now needs to handle correct shutdown logic etc. themselves. This is documented at: https://docs.aiohttp.org/en/stable/web_advanced.html#application-runners
Is your feature request related to a problem?
Most of the server examples in the documentation are based on a somewhat restrictive pattern of running an HTTP[S] server largely in isolation, with no easy way to have it interacting with other components.
This leaves a huge gap for real world usage. In countless cases, developers want to implement a web server, but also connect it to other clients and/or servers and/or data sources.
Developers usually don't want to be caught in a pattern where the web server is the "star attraction", and difficult to connect to other elements. They'd rather have the web server running in and around numerous elements, and able to freely exchange data and control with them.
I've written an example (see section below) for how to make aiohttp easier to integrate with other asyncio elements.
Describe the solution you'd like
I recommend the documentation be updated to include an example, such as what I've provided below, of how to run an HTTP server in a way that makes it very simple to integrate with other program elements running in the asyncio environment.
This will help other developers to incorporate aiohttp-based servers in with their other work, much more easily and quickly, than digging through the aiohttp code to figure out how to adapt it to their patterns.
Describe alternatives you've considered
Here is my implementation of a very minimal server. Feel free to use it verbatim, or with adaptations, in the aiohttp documentation. The focus for this demo is making it very trivial to integrate with other asyncio elements, and support a broader range of programming patterns.
Related component
Server
Additional context
No response
Code of Conduct
The text was updated successfully, but these errors were encountered: