Skip to content

Commit

Permalink
Style and grammar fixes/improvements on the FAQ page
Browse files Browse the repository at this point in the history
  • Loading branch information
sloria committed May 26, 2018
1 parent 31d1138 commit ec5f8fc
Showing 1 changed file with 107 additions and 110 deletions.
217 changes: 107 additions & 110 deletions docs/faq.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@ FAQ
.. contents::
:local:

Are there any plans for @app.route decorator like in Flask?
-----------------------------------------------------------
Are there plans for an @app.route decorator like in Flask?
----------------------------------------------------------

We have it already (*aiohttp>=2.3* required):
As of aiohttp 2.3, :class:`~aiohttp.web.RouteTableDef` provides an API
similar to Flask's ``@app.route``. See
:ref:`aiohttp-web-alternative-routes-definition`.

The difference is: ``@app.route`` should have an ``app`` in module
global namespace, which makes *circular import hell* easy.
Unlike Flask's ``@app.route``, :class:`~aiohttp.web.RouteTableDef`
does not require an ``app`` in the module namespace (which often leads
to circular imports).

*aiohttp* provides a :class:`~aiohttp.web.RouteTableDef` decoupled
from an application instance::
Instead, a :class:`~aiohttp.web.RouteTableDef` is decoupled from an application instance::

routes = web.RouteTableDef()

Expand All @@ -30,36 +31,35 @@ global namespace, which makes *circular import hell* easy.
app.router.add_routes(routes)


Has aiohttp the Flask Blueprint or Django App concept?
------------------------------------------------------
Does aiohttp have a concept like Flask's "blueprint" or Django's "app"?
-----------------------------------------------------------------------

If you're planing to write big applications, maybe you must consider
use nested applications. They acts as a Flask Blueprint or like the
Django application concept.
If you're writing a large application, you may want to consider
using :ref:`nested applications <aiohttp-web-nested-applications>`, which
are similar to Flask's "blueprints" or Django's "apps".

Using nested application you can add sub-applications to the main application.
See: :ref:`aiohttp-web-nested-applications`.

see: :ref:`aiohttp-web-nested-applications`.

How do I create a route that matches urls with a given prefix?
--------------------------------------------------------------

How to create route that catches urls with given prefix?
---------------------------------------------------------
Try something like::
You can do something like the following: ::

app.router.add_route('*', '/path/to/{tail:.+}', sink_handler)

Where first argument, star, means catch any possible method
(*GET, POST, OPTIONS*, etc), second matching ``url`` with desired prefix,
third -- handler.
The first argument, ``*``, matches any HTTP method
(*GET, POST, OPTIONS*, etc). The second argument matches URLS with the desired prefix.
The third argument is the handler function.


Where to put my database connection so handlers can access it?
--------------------------------------------------------------
Where do I put my database connection so handlers can access it?
----------------------------------------------------------------

:class:`aiohttp.web.Application` object supports :class:`dict`
interface, and right place to store your database connections or any
other resource you want to share between handlers. Take a look on
following example::
:class:`aiohttp.web.Application` object supports the :class:`dict`
interface and provides a place to store your database connections or any
other resource you want to share between handlers.
::

async def go(request):
db = request.app['db']
Expand All @@ -77,71 +77,70 @@ following example::
return app


Why the minimal supported version is Python 3.5.3?
--------------------------------------------------
Why is Python 3.5.3 the lowest supported version?
-------------------------------------------------

Python 3.5.2 has fixed protocol for async iterators: ``__aiter()__`` is
not a coroutine but regular function.
Python 3.5.2 fixes the protocol for async iterators: ``__aiter()__`` is
not a coroutine but a regular function.

Python 3.5.3 is even more important: :func:`asyncio.get_event_loop`
Python 3.5.3 has a more important change: :func:`asyncio.get_event_loop`
returns the running loop instance if called from a coroutine
(previously was returning a *default* one, set by
Previously it returned a *default* loop, set by
:func:`asyncio.set_event_loop`.

The change is very crucial, in Python < 3.5.3
:func:`asyncio.get_event_loop` was not reliable, thus user *was
forced* to pass the event loop instance explicitly everywhere.

Otherwise if a future object was created for using one event loop
(e.g. default) but a coroutine was run by other loop -- the coroutine
was never awaited, task was *hung*.
Previous to Python 3.5.3,
:func:`asyncio.get_event_loop` was not reliable, so users were
forced to explicitly pass the event loop instance everywhere.
If a future object were created for one event loop
(e.g. the default loop) but a coroutine was run by another loop, the coroutine
was never awaited. As a result, the task would hang.

Keep in mind that every ``await`` expression internally either passed
instantly or paused by waiting for a future.
Keep in mind that every internal ``await`` expression either passed
instantly or paused, waiting for a future.

It's extremely important that all tasks (coroutine runners) and
futures are using the same event loop.
futures use the same event loop.


How a middleware may store a data for using by web-handler later?
-----------------------------------------------------------------
How can middleware store data for web handlers to use?
------------------------------------------------------

:class:`aiohttp.web.Request` supports :class:`dict` interface as well
as :class:`aiohttp.web.Application`.
Both :class:`aiohttp.web.Request` and :class:`aiohttp.web.Application`
support the :class:`dict` interface.

Just put data inside *request*::
Therefore, data may be stored inside a request object. ::

async def handler(request):
request['unique_key'] = data

See https://github.com/aio-libs/aiohttp_session code for inspiration,
``aiohttp_session.get_session(request)`` method uses ``SESSION_KEY``
for saving request specific session info.
See https://github.com/aio-libs/aiohttp_session code for an example.
The ``aiohttp_session.get_session(request)`` method uses ``SESSION_KEY``
for saving request-specific session information.

As of aiohttp 3.0 all response objects are *dict-like* structures as
As of aiohttp 3.0, all response objects are dict-like structures as
well.


.. _aiohttp_faq_parallel_event_sources:

How to receive an incoming events from different sources in parallel?
---------------------------------------------------------------------
Can a handler receive incoming events from different sources in parallel?
-------------------------------------------------------------------------

For example we have two event sources:
Yes.

1. WebSocket for event from end user
As an example, we may have two event sources:

2. Redis PubSub from receiving events from other parts of app for
sending them to user via websocket.
1. WebSocket for events from an end user

The most native way to perform it is creation of separate task for
pubsub handling.
2. Redis PubSub for events from other parts of the application

Parallel :meth:`aiohttp.web.WebSocketResponse.receive` calls are forbidden, only
the single task should perform websocket reading.
The most native way to handle this is to create a separate task for
PubSub handling.

But other tasks may use the same websocket object for sending data to
peer::
Parallel :meth:`aiohttp.web.WebSocketResponse.receive` calls are forbidden;
a single task should perform WebSocket reading.
However, other tasks may use the same WebSocket object for sending data to
peers. ::

async def handler(request):

Expand Down Expand Up @@ -172,18 +171,17 @@ peer::

.. _aiohttp_faq_terminating_websockets:

How to programmatically close websocket server-side?
----------------------------------------------------

How do I programmatically close a WebSocket server-side?
--------------------------------------------------------

For example we have an application with two endpoints:
Let's say we have an application with two endpoints:


1. ``/echo`` a websocket echo server that authenticates the user somehow
2. ``/logout_user`` that when invoked needs to close all open
websockets for that user.
1. ``/echo`` a WebSocket echo server that authenticates the user
2. ``/logout_user`` that, when invoked, closes all open
WebSockets for that user.

One simple solution is keeping a shared registry of websocket
One simple solution is to keep a shared registry of WebSocket
responses for a user in the :class:`aiohttp.web.Application` instance
and call :meth:`aiohttp.web.WebSocketResponse.close` on all of them in
``/logout_user`` handler::
Expand Down Expand Up @@ -227,11 +225,11 @@ and call :meth:`aiohttp.web.WebSocketResponse.close` on all of them in
web.run_app(app, host='localhost', port=8080)


How to make request from a specific IP address?
-----------------------------------------------
How do I make a request from a specific IP address?
---------------------------------------------------

If your system has several IP interfaces you may choose one which will
be used used to bind socket locally::
If your system has several IP interfaces, you may choose one which will
be used used to bind a socket locally::

conn = aiohttp.TCPConnector(local_addr=('127.0.0.1', 0), loop=loop)
async with aiohttp.ClientSession(connector=conn) as session:
Expand All @@ -240,18 +238,18 @@ be used used to bind socket locally::
.. seealso:: :class:`aiohttp.TCPConnector` and ``local_addr`` parameter.


API stability and deprecation policy
------------------------------------
What is the API stability and deprecation policy?
-------------------------------------------------

*aiohttp* follows strong [SemVer](https://semver.org/) schema.
*aiohttp* follows strong `Semantic Versioning <https://semver.org>`_ (SemVer).

Obsolete attributes and methods are marked as *deprecated* in
documentation and raises :class:`DeprecationWarning` on usage.
Obsolete attributes and methods are marked as *deprecated* in the
documentation and raise :class:`DeprecationWarning` upon usage.

Let's assume now we have aiohttp ``X.Y.Z`` where ``X`` is *major* version,
Assume aiohttp ``X.Y.Z`` where ``X`` is major version,
``Y`` is minor version and ``Z`` is bugfix number.

E.g. now the latest released version is ``aiohttp==3.0.6``.
For example, if the latest released version is ``aiohttp==3.0.6``:

``3.0.7`` fixes some bugs but have no new features.

Expand All @@ -262,61 +260,60 @@ remove it, also all bug fixes from previous release are merged.
**except** deprecations from the **last** ``3.Y`` release. These
deprecations will be removed by ``5.0.0``.

Unfortunately we have break the rules in case of found **security
vulnerability**.

Unfortunately we may have to break these rules when a **security
vulnerability** is found.
If a security problem cannot be fixed without breaking backward
compatibility -- a bugfix release may do it. The probability for this
is very low but shit happens, sorry.
compatibility, a bugfix release may break compatibility. This is unlikely, but
possible.

All *backward incompatible* changes are explicitly marked in
:ref:`CHANGES <aiohttp_changes>` chapter.
All backward incompatible changes are explicitly marked in
:ref:`the changelog <aiohttp_changes>`.


How to enable gzip compression globally for the whole application?
------------------------------------------------------------------
How do I enable gzip compression globally for my entire application?
--------------------------------------------------------------------

It's impossible. Choosing what to compress and where don't apply such
time consuming operation is very tricky matter.
It's impossible. Choosing what to compress and what not to compress is
is a tricky matter.

If you need global compression -- write own custom middleware. Or
If you need global compression, write a custom middleware. Or
enable compression in NGINX (you are deploying aiohttp behind reverse
proxy, is not it).
proxy, right?).


How to manage ClientSession inside web server?
----------------------------------------------
How do I manage a ClientSession within a web server?
----------------------------------------------------

:class:`aiohttp.ClientSession` should be created once for the lifetime
of the server in order to benefit from connection pooling.

Session saves cookies internally. If you don't need cookies processing
Sessions save cookies internally. If you don't need cookie processing,
use :class:`aiohttp.DummyCookieJar`. If you need separate cookies
for different http calls but process them in logical chains use single
for different http calls but process them in logical chains, use a single
:class:`aiohttp.TCPConnector` with separate
client session and ``own_connector=False``.
client sessions and ``own_connector=False``.


How to access db connection stored in app from subapplication?
--------------------------------------------------------------
How do I access database connections from a subapplication?
-----------------------------------------------------------

Restricting access from subapplication to main (or outer) app is the
Restricting access from subapplication to main (or outer) app is a
deliberate choice.

Subapplication is an isolated unit by design. If you need to share
database object please do it explicitly::
A subapplication is an isolated unit by design. If you need to share a
database object, do it explicitly::

subapp['db'] = mainapp['db']
mainapp.add_subapp('/prefix', subapp)


How to perform operations in request handler after sending the response?
------------------------------------------------------------------------
How do I perform operations in a request handler after sending the response?
----------------------------------------------------------------------------

Middlewares can be written to handle post-response operations, but
they run after every request. You can explicitly send the response by
calling :meth:`aiohttp.web.Response.write_eof`, which starts sending
before the handler returns, giving you space to add follow-up
before the handler returns, giving you a chance to execute follow-up
operations::

def ping_handler(request):
Expand All @@ -332,6 +329,6 @@ operations::

return resp

The :class:`aiohttp.web.Response` object must be returned. This is
required by aiohttp web contracts, but actually the response has
A :class:`aiohttp.web.Response` object must be returned. This is
required by aiohttp web contracts, even though the response
already been sent.

0 comments on commit ec5f8fc

Please sign in to comment.