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