Changelog for Falcon 4.3.0#
Summary#
Falcon 4.3.0 centers on request parsing and typing. On the parsing side, this
release introduces a family of new Request methods for
extracting structured data from the query string –
get_param_as_dict(),
get_param_as_media(), and
get_query_string_as_media() – together with a new
delimiter argument for get_param_as_list(). Several of
these align with OpenAPI v3 (and 3.2) parameter styles, making it easier to
implement spec-compliant APIs on top of Falcon.
On the typing side, our internal annotations are now strict enough for the
project to pass mypy --strict falcon/, and generic App types are now automatically parametrized by the default
request/response types on CPython 3.13+.
This release also brings a number of smaller improvements, including MessagePack
support in the test client, an opt-in on_request() default responder, and
hardening of falcon.secure_filename() against Windows reserved device
names.
Two features that we had hoped to land in 4.3 – response teardown callbacks and a native OpenTelemetry integration – did not make the cut in time. Both are now at the top of our priority list for Falcon 4.4.
On the security front, our GitHub Actions workflows are now audited with zizmor, and we have hardened the existing workflows to address the issues it surfaced.
This release also incorporates many pull requests submitted by our community. Sincere thanks to all 19 contributors who made this release possible!
New & Improved#
The test client (
simulate_request()and friends) now accepts amsgpackkeyword argument, analogous to the existingjsonone. When provided, the value is serialized as a MessagePack document and used as the request body, and theContent-Typeheader is set toMEDIA_MSGPACK. (#1026)A new router option,
default_to_on_request, was added to allow resources to provide a default responder viaon_request()(disabled by default). When enabled,on_request()is used as the default responder for every HTTP method that lacks an explicit responder, exceptOPTIONS(served byon_options()) and the special WebSocket handler (on_websocket()).When the option is disabled, or the
on_request()method is not implemented, the default responder for"405 Method Not Allowed"is used. (#2071)On Windows,
falcon.secure_filename()now escapes reserved device names (CON,NUL,COM1, etc.) by prefixing the sanitized value with an underscore. (#2422)Internal type annotations were improved, allowing the project to pass
mypy --strict falcon/. We have added a few# type: ignorecomments for known limitations, and are actively working to reduce their necessity. (#2504)The
get_param_as_list()method now supports a new argument,delimiter, for splitting values. In line with the OpenAPI v3 parameter specification, the supported delimiters currently include the'pipeDelimited'and'spaceDelimited'symbolic constants, as well as the literal',','|', and' 'characters. (#2538)A new
get_param_as_dict()method was added toRequestthat retrieves a query parameter as adict. Two input formats are supported: an alternating key/value list (e.g.param=k1,v1,k2,v2) and, whendeep_objectis set, the OpenAPI v3deepObjectstyle (e.g.param[k1]=v1¶m[k2]=v2). (#2542)A new
get_query_string_as_media()method was added toRequest. The method URL-decodes the entire query string and deserializes it using the configured media handlers. This is useful for implementing the OpenAPI 3.2 querystring parameter location, where the entire query string is treated as a single serialized value. (#2546)A new
get_param_as_media()method was added toRequest. It deserializes a single query-string parameter using the configured media handlers, and accepts an optionalmedia_typethat falls back to the app’sdefault_media_typewhen unspecified. (#2549)A new request property,
req.last_event_id, was added to provide convenient access to theLast-Event-IDheader. This header is commonly sent by clients when reconnecting to aServer-Sent Eventsstream. (#2580)Generic App types are now automatically parametrized by the default request/response types (unless specified otherwise), courtesy of
TypeVar’s default value support on CPython 3.13+. (#2586)
Fixed#
Due to differences in interpretation of the ASGI specification, Uvicorn could set
clientin the HTTP connection scope in a way that brokereq.access_routeandreq.remote_addrwhen the app server was bound to a Unix domain socket.This discrepancy was addressed, and Falcon should now fall back to the same default value (
'127.0.0.1') in this case as ifclientwas missing altogether. (#2583)
Misc#
Documented the US-ASCII restriction on the
nameandvaluearguments offalcon.Response.set_cookie(). The implementation has always rejected non-ASCII inputs (raisingKeyErrorfornameandValueErrorforvalue), but the parameter andRaisesentries did not call this out; the docstring now matches the runtime behaviour. (#1445)The
falcon.testing.redirected()context manager has been deprecated in favor of the standard library’scontextlib.redirect_stdout()andcontextlib.redirect_stderr(). It is scheduled for removal in Falcon 5.0. (#2569)Falcon no longer adds an instance of
logging.NullHandlerto thefalconlogger, so ASGI application tracebacks may now reachsys.stderrvia thelogging.lastResorthandler in the absence of configuration (see also: Debugging ASGI Applications). (#2594)falcon.sys(an internal re-export of the standard library’ssysmodule that was added inadvertently long ago) is scheduled for removal in Falcon 5.0. Import the standard library’ssysmodule directly instead. (#2630)Our GitHub Actions workflows are now audited with zizmor, a static analysis tool that catches common security pitfalls in CI/CD pipelines. The audit runs both as a dedicated workflow and as part of our
toxchecks, and the existing workflows were hardened to address the issues it surfaced. (#2651)
Contributors to this Release#
Many thanks to all of our talented and stylish contributors for this release!