1Changelog for Falcon 2.0.0
2==========================
3
4Summary
5-------
6
7Many thanks to all of our awesome contributors (listed down below) who made
8this release possible!
9
10In 2.0 we added a number of new convenience methods and properties. We also
11made it a lot cleaner and less error-prone to assign multiple routes to the
12same resource class via suffixed responders.
13
14Also noteworthy is the significant effort we invested in improving the
15accuracy, clarity, and breadth of the docs. We hope these changes will help
16make the framework easier to learn for newcomers.
17
18Middleware methods can now short-circuit request processing, and we improved
19cookie and ETag handling. Plus, the testing framework received several
20improvements to make it easier to simulate certain types of requests.
21
22As this is the first major release that we have had in quite a while, we have
23taken the opportunity to clean up many parts of the framework. Deprecated
24variables, methods, and classes have been removed, along with all
25backwards-compatibility shims for old method signatures. We also changed the
26defaults for a number of request options based on community feedback.
27
28Please carefully review the list of breaking changes below to see what
29you may need to tweak in your app to make it compatible with this release.
30
31Changes to Supported Platforms
32------------------------------
33
34- CPython 3.7 is now fully supported.
35- Falcon 2.x series is the last to support Python language version 2. As a
36  result, support for CPython 2.7 and PyPy2.7 will be removed in Falcon 3.0.
37- Support for CPython 3.4 is now deprecated and will be removed in Falcon 3.0.
38- Support for CPython 2.6, CPython 3.3 and Jython 2.7 has been dropped.
39
40Breaking Changes
41----------------
42
43- Previously, several methods in the :class:`~.Response` class
44  could be used to attempt to set raw cookie headers. However,
45  due to the Set-Cookie header values not being combinable
46  as a comma-delimited list, this resulted in an
47  incorrect response being constructed for the user agent in
48  the case that more than one cookie was being set. Therefore,
49  the following methods of ``falcon.Response`` now raise an
50  instance of ``ValueError`` if an attempt is made to use them
51  for Set-Cookie: :meth:`~.Response.set_header`,
52  :meth:`~.Response.delete_header`, :meth:`~.Response.get_header`,
53  :meth:`~.Response.set_headers`.
54- :attr:`falcon.testing.Result.json` now returns ``None`` when the response body is
55  empty, rather than raising an error.
56- :meth:`~.Request.get_param_as_bool` now defaults to treating valueless
57  parameters as truthy, rather than falsy. ``None`` is still returned
58  by default when the parameter is altogether missing.
59- :meth:`~.Request.get_param_as_bool` no longer raises an error for a
60  valueless parameter when the ``blank_as_true`` keyword argument is ``False``.
61  Instead, ``False`` is simply returned in that case.
62- :attr:`~.RequestOptions.keep_blank_qs_values` now defaults to ``True``
63  instead of ``False``.
64- :attr:`~.RequestOptions.auto_parse_qs_csv` now defaults to ``False``
65  instead of ``True``.
66- ``independent_middleware`` kwarg on :class:`falcon.API` now defaults to
67  ``True`` instead of ``False``.
68- The ``stream_len`` property of the :class:`~.Response` class was changed to
69  be an alias of the new :attr:`~.Response.content_length` property. Please
70  use :meth:`~.Response.set_stream` or :attr:`~.Response.content_length`
71  instead, going forward, as ``stream_len`` is now deprecated.
72- Request :attr:`~.Request.context_type` was changed from dict to a bare class
73  implementing the mapping interface.
74  (See also: :ref:`bare_class_context_type`)
75- Response :attr:`~.Response.context_type` was changed from dict to a bare class
76  implementing the mapping interface.
77  (See also: :ref:`bare_class_context_type`)
78- :class:`~.media.JSONHandler` and :class:`~.HTTPError` no longer use
79  `ujson` in lieu of the standard `json` library (when `ujson` is available in
80  the environment). Instead, :class:`~.media.JSONHandler` can now be configured
81  to use arbitrary ``dumps()`` and ``loads()`` functions. If you
82  also need to customize :class:`~.HTTPError` serialization, you can do so via
83  :meth:`~.API.set_error_serializer`.
84- The ``find()`` method for a custom router is now required to accept the
85  ``req`` keyword argument that was added in a previous release. The
86  backwards-compatible shim was removed.
87- All :ref:`middleware <middleware>` methods and :ref:`hooks <hooks>` must
88  now accept the arguments as specified in the relevant interface definitions
89  as of Falcon 1.4. All backwards-compatible shims have been removed.
90- Custom error serializers are now required to accept the arguments as
91  specified by :meth:`~.API.set_error_serializer` for the past few releases.
92  The backwards-compatible shim has been removed.
93- An internal function, ``make_router_search()``, was removed from the
94  ``api_helpers`` module.
95- An internal function, ``wrap_old_error_serializer()``, was removed from the
96  ``api_helpers`` module.
97- In order to improve performance, the :attr:`falcon.Request.headers` and
98  :attr:`falcon.Request.cookies` properties now return a direct reference to
99  an internal cached object, rather than making a copy each time. This
100  should normally not cause any problems with existing apps since these objects
101  are generally treated as read-only by the caller.
102- The :attr:`falcon.Request.stream` attribute is no longer wrapped in a bounded
103  stream when Falcon detects that it is running on the wsgiref server. If you
104  need to normalize stream semantics between wsgiref and a production WSGI
105  server, :attr:`~.Request.bounded_stream` may be used instead.
106- :attr:`falcon.Request.cookies` now gives precedence to the first value
107  encountered in the Cookie header for a given cookie name, rather than the
108  last.
109- The ordering of the parameters passed to custom error handlers was adjusted
110  to be more intuitive and consistent with the rest of the framework::
111
112    # Before
113    def handle_error(ex, req, resp, params):
114      pass
115
116    # Falcon 2.0
117    def handle_error(req, resp, ex, params):
118      pass
119
120  See also: :meth:`~.API.add_error_handler`
121
122- :attr:`~.falcon.RequestOptions.strip_url_path_trailing_slash` now defaults
123  to ``False`` instead of ``True``.
124- The deprecated ``falcon.testing.TestCase.api`` property was removed.
125- The deprecated ``falcon.testing.TestCase.api_class`` class variable was removed.
126- The deprecated ``falcon.testing.TestBase`` class was removed.
127- The deprecated ``falcon.testing.TestResource`` class was removed.
128- The deprecated ``protocol`` property was removed from the
129  :class:`~.Request` class.
130- The deprecated ``get_param_as_dict()`` method alias was removed from the
131  :class:`~.Request` class. Please use :meth:`~.Request.get_param_as_json`
132  instead.
133- Routers were previously allowed to accept additional args and
134  keyword arguments, and were not required to use the variadic form. Now,
135  they are only allowed to accept additional options as variadic keyword
136  arguments, and to ignore any arguments they don't support. This helps
137  overridden router logic be less fragile in terms of their interface
138  contracts, which also makes it easier to keep Falcon backwards-compatible
139  in the face of any future changes in this area.
140- :meth:`~.API.add_route` previously accepted `*args`, but now no longer does.
141- The ``add_route()`` method for custom routers no longer takes a `method_map`
142  argument. Custom routers should, instead, call the
143  :meth:`~falcon.routing.map_http_methods` function directly
144  from their ``add_route()`` method if they require this mapping.
145- The ``serialize()`` media handler method now receives an extra
146  `content_type` argument, while the ``deserialize()`` method now takes
147  `stream`, `content_type`, and `content_length` arguments, rather than a
148  single `raw` argument. The raw data can still be obtained by executing
149  ``raw = stream.read()``.
150
151  See also: :class:`~.media.BaseHandler`
152
153- The deprecated ``falcon.routing.create_http_method_map()`` method was
154  removed.
155- The keyword arguments for :meth:`~falcon.uri.parse_query_string` were renamed
156  to be more concise::
157
158    # Before
159    parsed_values = parse_query_string(
160        query_string, keep_blank_qs_values=True, parse_qs_csv=False
161    )
162
163    # Falcon 2.0
164    parsed_values = parse_query_string(
165        query_string, keep_blank=True, csv=False
166    )
167
168- :attr:`~.falcon.RequestOptions.auto_parse_qs_csv` now defaults
169  to ``False`` instead of ``True``.
170- The ``HTTPRequestEntityTooLarge`` class was renamed to
171  :class:`~falcon.HTTPPayloadTooLarge`.
172- Two of the keyword arguments for :meth:`~.Request.get_param_as_int` were
173  renamed to avoid shadowing built-in Python names::
174
175    # Before
176    dpr = req.get_param_as_int('dpr', min=0, max=3)
177
178    # Falcon 2.0
179    dpr = req.get_param_as_int('dpr', min_value=0, max_value=3)
180
181- The :meth:`falcon.media.validators.jsonschema.validate` decorator now uses
182  :meth:`functools.wraps` to make the decorated method look like the original.
183- Previously, :class:`~.HTTPError` instances for which the `has_representation`
184  property evaluated to ``False`` were not passed to custom error serializers
185  (such as in the case of types that subclass
186  :class:`~.NoRepresentation`). This has now been fixed so
187  that custom error serializers will be called for all instances of
188  :class:`~.HTTPError`.
189- Request cookie parsing no longer uses the standard library
190  for most of the parsing logic. This may lead to subtly different results
191  for archaic cookie header formats, since the new implementation is based on
192  RFC 6265.
193- The :attr:`~.Request.if_match` and :attr:`~.Request.if_none_match` properties
194  now return a list of :class:`falcon.ETag` objects rather than the raw
195  value of the If-Match or If-None-Match headers, respectively.
196- When setting the :attr:`~.Response.etag` header property, the value will
197  now be wrapped with double-quotes (if not already present) to ensure
198  compliance with RFC 7232.
199- The default error serializer no longer sets the `charset` parameter for the
200  media type returned in the Content-Type header, since UTF-8 is the default
201  encoding for both JSON and XML media types. This should not break
202  well-behaved clients, but could impact test cases in apps that
203  assert on the exact value of the Content-Type header.
204- Similar to the change made to the default error serializer, the default JSON
205  media type generally used for successful responses was also modified
206  to no longer specify the `charset` parameter.
207  This change affects both the :data:`falcon.DEFAULT_MEDIA_TYPE` and
208  :data:`falcon.MEDIA_JSON` :ref:`constants <media_type_constants>`, as well
209  as the default value of the `media_type` keyword argument specified for
210  the :class:`falcon.API` initializer. This change also affects the default
211  value of the :attr:`.RequestOptions.default_media_type` and
212  :attr:`.ResponseOptions.default_media_type` options.
213
214New & Improved
215--------------
216
217- Several performance optimizations were made to hot code paths in the
218  framework to make Falcon 2.0 even faster than 1.4 in some cases.
219- Numerous changes were made to the docs to improve clarity and to provide
220  better recommendations on how to best use various parts of the framework.
221- Added a new :attr:`~.Response.headers` property to the :class:`~.Response` class.
222- Removed the :py:mod:`six` and :py:mod:`python-mimeparse` dependencies.
223- Added a new :attr:`~.Response.complete` property to the :class:`~.Response`
224  class. This can be used to short-circuit request processing when the response
225  has been pre-constructed.
226- Request :attr:`~.Request.context_type` now defaults to a bare class allowing
227  to set attributes on the request context object::
228
229    # Before
230    req.context['role'] = 'trial'
231    req.context['user'] = 'guest'
232
233    # Falcon 2.0
234    req.context.role = 'trial'
235    req.context.user = 'guest'
236
237  To ease the migration path, the previous behavior is supported by
238  implementing the mapping interface in a way that object attributes and
239  mapping items are linked, and setting one sets the other as well. However, as
240  of Falcon 2.0, the dict context interface is considered deprecated, and may
241  be removed in a future release.
242
243  Applications can work around this change by explicitly overriding
244  :attr:`~.Request.context_type` to dict.
245  (See also: :ref:`bare_class_context_type`)
246- Response :attr:`~.Response.context_type` now defaults to a bare class allowing
247  to set attributes on the response context object::
248
249    # Before
250    resp.context['cache_strategy'] = 'lru'
251
252    # Falcon 2.0
253    resp.context.cache_strategy = 'lru'
254
255  To ease the migration path, the previous behavior is supported by
256  implementing the mapping interface in a way that object attributes and
257  mapping items are linked, and setting one sets the other as well. However, as
258  of Falcon 2.0, the dict context interface is considered deprecated, and may
259  be removed in a future release.
260
261  Applications can work around this change by explicitly overriding
262  :attr:`~.Response.context_type` to dict.
263  (See also: :ref:`bare_class_context_type`)
264- :class:`~.media.JSONHandler` can now be configured to use arbitrary
265  ``dumps()`` and ``loads()`` functions. This enables support not only for
266  using any of a number of third-party JSON libraries, but also for
267  customizing the keyword arguments used when (de)serializing objects.
268- Added a new method, :meth:`~.Request.get_cookie_values`, to the
269  :class:`~.Request` class. The new method supports getting all values
270  provided for a given cookie, and is now the preferred mechanism for
271  reading request cookies.
272- Optimized request cookie parsing. It is now roughly an order of magnitude
273  faster.
274- :meth:`~.Response.append_header` now supports appending raw Set-Cookie header values.
275- Multiple routes can now be added for the same resource instance using a
276  suffix to distinguish the set of responders that should be used. In this way,
277  multiple closely-related routes can be mapped to the same resource while
278  preserving readability and consistency.
279
280  See also: :meth:`~.API.add_route`
281
282- The :meth:`falcon.media.validators.jsonschema.validate` decorator now
283  supports both request and response validation.
284- A static route can now be configured to return the data from a default file
285  when the requested file path is not found.
286
287  See also: :meth:`~.API.add_static_route`
288
289- The ordering of the parameters passed to custom error handlers was adjusted
290  to be more intuitive and consistent with the rest of the framework::
291
292    # Before
293    def handle_error(ex, req, resp, params):
294      pass
295
296    # Falcon 2.0
297    def handle_error(req, resp, ex, params):
298      pass
299
300  See also: :meth:`~.API.add_error_handler`.
301
302- All error classes now accept a `headers` keyword argument for customizing
303  response headers.
304- A new method, :meth:`~.Request.get_param_as_float`, was added to the
305  :class:`~.Request` class.
306- A new method, :meth:`~.Request.has_param`, was added to the
307  :class:`~.Request` class.
308- A new property, :attr:`~.Response.content_length`, was added to the
309  :class:`~.Response` class. Either :meth:`~.Response.set_stream` or
310  :attr:`~.Response.content_length` should be used going forward, as
311  ``stream_len`` is now deprecated.
312- All ``get_param_*()`` methods of the :class:`~.Request` class now accept a
313  `default` argument.
314- A new header property, :attr:`~.Response.expires`, was added to the
315  :class:`~.Response` class.
316- The :class:`~.routing.CompiledRouter` class now exposes a
317  :class:`~falcon.routing.CompiledRouter.map_http_methods` method that child
318  classes can override in order to customize the mapping of HTTP methods to
319  resource class methods.
320- The ``serialize()`` media handler method now receives an extra
321  `content_type` argument, while the ``deserialize()`` method now takes
322  `stream`, `content_type`, and `content_length` arguments, rather than a
323  single `raw` argument. The raw data can still be obtained by executing
324  ``raw = stream.read()``.
325
326  See also: :class:`~.media.BaseHandler`
327
328- The :meth:`~.Response.get_header` method now accepts a `default` keyword
329  argument.
330- The :meth:`~falcon.testing.TestClient.simulate_request` method now supports
331  overriding the host and remote IP address in the WSGI environment, as well
332  as setting arbitrary additional CGI variables in the WSGI environment.
333- The :meth:`~falcon.testing.TestClient.simulate_request` method now supports
334  passing a query string as part of the path, as an alternative to using the
335  `params` or `query_string` keyword arguments.
336- Added a deployment guide to the docs for uWSGI and NGINX on Linux.
337- The :meth:`~.uri.decode` method now accepts an `unquote_plus` keyword
338  argument. The new argument defaults to ``False`` to avoid a breaking change.
339- The :meth:`~.Request.if_match` and :meth:`~.Request.if_none_match` properties
340  now return a list of :class:`falcon.ETag` objects rather than the raw
341  value of the If-Match or If-None-Match headers, respectively.
342- :meth:`~.API.add_error_handler` now supports specifying an iterable of
343  exception types to match.
344- The default error serializer no longer sets the `charset` parameter for the
345  media type returned in the Content-Type header, since UTF-8 is the default
346  encoding for both JSON and XML media types.
347- Similar to the change made to the default error serializer, the default JSON
348  media type generally used for successful responses was also modified
349  to no longer specify the `charset` parameter.
350  This change affects both the :data:`falcon.DEFAULT_MEDIA_TYPE` and
351  :data:`falcon.MEDIA_JSON` :ref:`constants <media_type_constants>`, as well
352  as the default value of the `media_type` keyword argument specified for
353  the :class:`falcon.API` initializer. This change also affects the default
354  value of the :attr:`.RequestOptions.default_media_type` and
355  :attr:`.ResponseOptions.default_media_type` options.
356
357Fixed
358-----
359
360- Fixed a docs issue where with smaller browser viewports, the API
361  documentation will start horizontal scrolling.
362- The color scheme for the docs was modified to fix issues with contrast and
363  readability when printing the docs or generating PDFs.
364- The :meth:`~falcon.testing.TestClient.simulate_request` method now forces
365  header values to `str` on Python 2 as required by PEP-3333.
366- The ``HTTPRequestEntityTooLarge`` class was renamed to
367  :class:`~falcon.HTTPPayloadTooLarge` and the reason phrase was updated
368  per RFC 7231.
369- The  :class:`falcon.CaseInsensitiveDict` class now inherits from
370  :class:`collections.abc.MutableMapping` under Python 3, instead of
371  :class:`collections.MutableMapping`.
372- The ``\ufffd`` character is now disallowed in requested static file paths.
373- The :meth:`falcon.media.validators.jsonschema.validate` decorator now uses
374  :meth:`functools.wraps` to make the decorated method look like the original.
375- The ``falcon-print-routes`` CLI tool no longer raises an unhandled error
376  when Falcon is cythonized.
377- The plus character (``'+'``) is no longer unquoted in the request path, but
378  only in the query string.
379- Previously, :class:`~.HTTPError` instances for which the `has_representation`
380  property evaluated to ``False`` were not passed to custom error serializers
381  (such as in the case of types that subclass
382  :class:`~.NoRepresentation`). This has now been fixed so
383  that custom error serializers will be called for all instances of
384  :class:`~.HTTPError`.
385- When setting the :attr:`~.Response.etag` header property, the value will
386  now be wrapped with double-quotes (if not already present) to ensure
387  compliance with RFC 7232.
388- Fixed ``TypeError`` being raised when using Falcon's testing framework
389  to simulate a request to a generator-based WSGI app.
390
391Contributors to this Release
392----------------------------
393
394Many thanks to all of our talented and stylish contributors for this release!
395
396- Bertrand Lemasle
397- `CaselIT <https://github.com/CaselIT>`_
398- `DmitriiTrofimov <https://github.com/DmitriiTrofimov>`_
399- `KingAkeem <https://github.com/KingAkeem>`_
400- `Nateyo <https://github.com/Nateyo>`_
401- Patrick Schneeweis
402- `TheMushrr00m <https://github.com/TheMushrr00m>`_
403- `ZDBioHazard <https://github.com/ZDBioHazard>`_
404- `alysivji <https://github.com/alysivji>`_
405- `aparkerlue <https://github.com/aparkerlue>`_
406- `astonm <https://github.com/astonm>`_
407- `awbush <https://github.com/awbush>`_
408- `bendemaree <https://github.com/bendemaree>`_
409- `bkcsfi <https://github.com/bkcsfi>`_
410- `brooksryba <https://github.com/brooksryba>`_
411- `carlodri <https://github.com/carlodri>`_
412- `grktsh <https://github.com/grktsh>`_
413- `hugovk <https://github.com/hugovk>`_
414- `jmvrbanac <https://github.com/jmvrbanac>`_
415- `kandziu <https://github.com/kandziu>`_
416- `kgriffs <https://github.com/kgriffs>`_
417- `klardotsh <https://github.com/klardotsh>`_
418- `mikeylight <https://github.com/mikeylight>`_
419- `mumrau <https://github.com/mumrau>`_
420- `nZac <https://github.com/nZac>`_
421- `navyad <https://github.com/navyad>`_
422- `ozzzik <https://github.com/ozzzik>`_
423- `paneru-rajan <https://github.com/paneru-rajan>`_
424- `safaozturk93 <https://github.com/safaozturk93>`_
425- `santeyio <https://github.com/santeyio>`_
426- `sbensoussan <https://github.com/sbensoussan>`_
427- `selfvin <https://github.com/selfvin>`_
428- `snobu <https://github.com/snobu>`_
429- `steven-upside <https://github.com/steven-upside>`_
430- `tribals <https://github.com/tribals>`_
431- `vytas7 <https://github.com/vytas7>`_
432