Skip to content

Commit

Permalink
docs: iron out some miscellaneous documentation issues (#1976)
Browse files Browse the repository at this point in the history
* docs: fix and improve miscellaneous documentation issues

* docs: more docs polish

* docs(CORS): improve the note on usage

* docs(CORS): remove a distracting sentence

* docs(FAQ): address a part of review comments

* docs: add more polish according to PR comments
  • Loading branch information
vytas7 authored Oct 26, 2021
1 parent 843802a commit 02942f3
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 39 deletions.
12 changes: 8 additions & 4 deletions docs/api/cors.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ CORS
(CORS) is an additional security check performed by modern
browsers to prevent unauthorized requests between different domains.

When implementing
a web API, it is common to have to also implement a CORS policy. Therefore,
Falcon provides an easy way to enable a simple CORS policy via a flag passed
to :class:`falcon.App` or :class:`falcon.asgi.App`.
When developing a web API, it is common to also implement a CORS
policy. Therefore, Falcon provides an easy way to enable a simple CORS policy
via a flag passed to :class:`falcon.App` or :class:`falcon.asgi.App`.

By default, Falcon's built-in CORS support is disabled, so that any cross-origin
requests will be blocked by the browser. Passing ``cors_enable=True`` will
Expand Down Expand Up @@ -60,6 +59,11 @@ Usage
app = falcon.asgi.App(middleware=falcon.CORSMiddleware(
allow_origins='example.com', allow_credentials='*'))
.. note::
Passing the ``cors_enable`` parameter set to ``True`` should be seen as
mutually exclusive with directly passing an instance of
:class:`~falcon.CORSMiddleware` to the application's initializer.

CORSMiddleware
--------------

Expand Down
3 changes: 3 additions & 0 deletions docs/api/routing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,9 @@ specifications in the URI template:
some_resource
)
(See also how :class:`~.UUIDConverter` is used in Falcon's ASGI tutorial:
:ref:`asgi_tutorial_image_resources`.)

.. _routing_builtin_converters:

Built-in Converters
Expand Down
2 changes: 1 addition & 1 deletion docs/api/websocket.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ ASGI application and a web browser, mobile app, or other client application.
.. note::

See also :attr:`falcon.asgi.Response.sse` to learn more about Falcon's
Server-Sent Event (SSE) support,
Server-Sent Event (SSE) support.

Usage
-----
Expand Down
84 changes: 52 additions & 32 deletions docs/user/faq.rst
Original file line number Diff line number Diff line change
Expand Up @@ -401,8 +401,8 @@ How can I pass data from a hook to a responder, and between hooks?
------------------------------------------------------------------
You can inject extra responder kwargs from a hook by adding them
to the *params* dict passed into the hook. You can also set custom attributes
on the ``req.context`` object, as a way of passing contextual information
around:
on the :attr:`req.context <falcon.Request.context>` object, as a way of passing
contextual information around:

.. code:: python
Expand Down Expand Up @@ -439,7 +439,7 @@ plain HTTP 500 error. To provide your own 500 logic, you can add a custom error
handler for Python's base :class:`Exception` type. This will not affect the
default handlers for :class:`~.HTTPError` and :class:`~.HTTPStatus`.

See :ref:`errors` and the :meth:`falcon.API.add_error_handler` docs for more
See :ref:`errors` and the :meth:`falcon.App.add_error_handler` docs for more
details.

Request Handling
Expand All @@ -449,7 +449,8 @@ How do I authenticate requests?
-------------------------------
Hooks and middleware components can be used together to authenticate and
authorize requests. For example, a middleware component could be used to
parse incoming credentials and place the results in ``req.context``.
parse incoming credentials and place the results in
:attr:`req.context <falcon.Request.context>`.
Downstream components or hooks could then use this information to
authorize the request, taking into account the user's role and the requested
resource.
Expand Down Expand Up @@ -558,8 +559,7 @@ installed by default, thus making the POSTed form available as

POSTed form parameters may also be read directly from
:attr:`~falcon.Request.stream` and parsed via
:meth:`falcon.uri.parse_query_string` or
`urllib.parse.parse_qs() <https://docs.python.org/3.6/library/urllib.parse.html#urllib.parse.parse_qs>`_.
:meth:`falcon.uri.parse_query_string` or :func:`urllib.parse.parse_qs`.

.. _access_multipart_files:

Expand Down Expand Up @@ -663,7 +663,7 @@ below:
}
app = falcon.API()
app = falcon.App()
app.add_route('/locations', LocationResource())
In the example above, ``LocationResource`` expects a query string containing
Expand Down Expand Up @@ -768,62 +768,82 @@ types:
Response Handling
~~~~~~~~~~~~~~~~~

When would I use media, data, and stream?
-----------------------------------------
When would I use media, data, text, and stream?
-----------------------------------------------

These three parameters are mutually exclusive, you should only set one when
These four attributes are mutually exclusive, you should only set one when
defining your response.

:ref:`resp.media <media>` is used when you want to use the Falcon serialization
mechanism. Just assign data to the attribute and falcon will take care of the
rest.
:attr:`resp.media <falcon.Response.media>` is used when you want to use the
Falcon serialization mechanism. Just assign data to the attribute and Falcon
will take care of the rest.

.. code:: python
class MyResource:
def on_get(self, req, resp):
resp.media = { 'hello': 'World' }
resp.media = {'hello': 'World'}
`resp.text` and `resp.data` are very similar, they both allow you to set the
body of the response. The difference being, `text` takes a string and `data`
:attr:`resp.text <falcon.Response.text>` and
:attr:`resp.data <falcon.Response.data>` are very similar, they both allow you
to set the body of the response. The difference being,
:attr:`~falcon.Response.text` takes a string, and :attr:`~falcon.Response.data`
takes bytes.

.. code:: python
class MyResource:
def on_get(self, req, resp):
resp.text = json.dumps({ 'hello': 'World' })
resp.text = json.dumps({'hello': 'World'})
def on_post(self, req, resp):
resp.data = b'{ "hello": "World" }'
resp.data = b'{"hello": "World"}'
`resp.stream` allows you to set a file-like object which returns bytes. We will
call `read()` until the object is consumed.
:attr:`resp.stream <falcon.Response.stream>` allows you to set a generator that
yields bytes, or a file-like object with a ``read()`` method that returns
bytes. In the case of a file-like object, the framework will call ``read()``
until the stream is exhausted.

.. code:: python
class MyResource:
def on_get(self, req, resp):
resp.stream = open('myfile.json', mode='rb')
See also the :ref:`outputting_csv_recipe` recipe for an example of using
:attr:`resp.stream <falcon.Response.stream>` with a generator.

How can I use resp.media with types like datetime?
--------------------------------------------------

The default JSON handler for ``resp.media`` only supports the objects and types
listed in the table documented under
`json.JSONEncoder <https://docs.python.org/3.6/library/json.html#json.JSONEncoder>`_.
To handle additional types, you can either serialize them beforehand, or create
a custom JSON media handler that sets the `default` param for ``json.dumps()``.
When deserializing an incoming request body, you may also wish to implement
`object_hook` for ``json.loads()``. Note, however, that setting the `default` or
`object_hook` params can negatively impact the performance of (de)serialization.
The default JSON handler for :attr:`resp.media <falcon.Response.media>` only
supports the objects and types listed in the table documented under
:any:`json.JSONEncoder`.

To handle additional types in JSON, you can either serialize them beforehand,
or create a custom JSON media handler that sets the `default` param for
:func:`json.dumps`. When deserializing an incoming request body, you may also
wish to implement `object_hook` for :func:`json.loads`. Note, however, that
setting the `default` or `object_hook` params can negatively impact the
performance of (de)serialization.

If you use an alternative JSON library, you might also look whether it provides
support for additional data types. For instance, the popular ``orjson`` opts to
automatically serialize :mod:`dataclasses`, :mod:`enums <enum>`,
:class:`~datetime.datetime` objects, etc.

Furthermore, different Internet media types such as YAML,
:class:`msgpack <falcon.media.MessagePackHandler>`, etc might support more data
types than JSON, either as part of the respective (de)serialization format, or
via custom type extensions.

Does Falcon set Content-Length or do I need to do that explicitly?
------------------------------------------------------------------
Falcon will try to do this for you, based on the value of ``resp.text`` or
``resp.data`` (whichever is set in the response, checked in that order.)
Falcon will try to do this for you, based on the value of
:attr:`resp.text <falcon.Response.text>`,
:attr:`resp.data <falcon.Response.data>` or
:attr:`resp.media <falcon.Response.media>` (whichever is set in the response,
checked in that order).

For dynamically-generated content, you can choose to not set
:attr:`~falcon.Response.content_length`, in which case Falcon will then leave
Expand Down Expand Up @@ -987,7 +1007,7 @@ When it comes to app configuration, Falcon is not opinionated. You are free to
choose from any of the excellent general-purpose configuration libraries
maintained by the Python community. It’s pretty much up to you if you want to
use the standard library or something like ``aumbry`` as demonstrated by this
`falcon example app <https://github.com/jmvrbanac/falcon-example/tree/master/example>`_
`Falcon example app <https://github.com/jmvrbanac/falcon-example/tree/master/example>`_.

(See also the **Configuration** section of our
`Complementary Packages wiki page <https://github.com/falconry/falcon/wiki/Complementary-Packages>`_.
Expand Down
2 changes: 1 addition & 1 deletion docs/user/intro.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ take care to keep logic paths within the framework simple, shallow and
understandable. All of this makes it easier to reason about the code and to
debug edge cases in large-scale deployments.

**Flexible.** Falcon leaves a lot of decisions and i`mplementation
**Flexible.** Falcon leaves a lot of decisions and implementation
details to you, the API developer. This gives you a lot of freedom to
customize and tune your implementation. Due to Falcon's minimalist
design, Python community members are free to independently innovate on
Expand Down
2 changes: 2 additions & 0 deletions docs/user/tutorial-asgi.rst
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,8 @@ processing.
to be picklable (which also implies that the task must be reachable from the
global namespace, i.e., an anonymous ``lambda`` simply won't work).

.. _asgi_tutorial_image_resources:

Images Resource(s)
------------------

Expand Down
2 changes: 1 addition & 1 deletion examples/things.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def on_get(self, req, resp):
)


# falcon.API instances are callable WSGI apps
# falcon.App instances are callable WSGI apps
# in larger applications the app is created in a separate file
app = falcon.App()

Expand Down

0 comments on commit 02942f3

Please sign in to comment.